From edee6d875285ca6aac8a8d3c6b218b62e7e3396d Mon Sep 17 00:00:00 2001 From: Adam Anderson <6754028+AdamEAnderson@users.noreply.github.com> Date: Wed, 6 May 2026 22:04:28 +0000 Subject: [PATCH 1/5] dynamic modules: refactor go sdk to prep for rust port Signed-off-by: Adam Anderson <6754028+AdamEAnderson@users.noreply.github.com> --- source/extensions/dynamic_modules/BUILD | 46 +- .../sdk/go/abi/{internal.go => http.go} | 1359 ++++++++++------- .../dynamic_modules/sdk/go/abi/network.go | 64 +- .../dynamic_modules/sdk/go/abi/scheduler.go | 74 + .../dynamic_modules/sdk/go/shared/api.go | 225 --- .../{fake_stream_base.go => fake_http.go} | 5 + ..._stream_base_test.go => fake_http_test.go} | 0 .../sdk/go/shared/{base.go => http.go} | 860 +++++------ .../sdk/go/shared/mocks/mock_api.go | 267 ---- .../mocks/{mock_base.go => mock_http.go} | 571 +++---- .../sdk/go/shared/mocks/mock_network_api.go | 220 +++ .../sdk/go/shared/mocks/mock_network_base.go | 991 ++++++++++++ .../sdk/go/shared/mocks/mock_types.go | 173 +++ .../sdk/go/shared/network_api.go | 1 + .../sdk/go/shared/network_base.go | 1 + .../dynamic_modules/sdk/go/shared/types.go | 336 ++++ test/extensions/dynamic_modules/http/BUILD | 14 +- .../dynamic_modules/http/integration_test.cc | 195 +++ test/extensions/dynamic_modules/network/BUILD | 5 +- .../network/integration_test.cc | 58 + .../dynamic_modules/test_data/go/BUILD | 2 + .../http_integration_test.go | 157 ++ .../http_stream_callouts_test.go | 351 +++++ .../network_integration_test.go | 85 ++ .../test_data/go/test_data.bzl | 20 +- .../test_data/rust/http_integration_test.rs | 155 ++ .../rust/network_integration_test.rs | 73 + tools/spelling/spelling_dictionary.txt | 5 + 28 files changed, 4472 insertions(+), 1841 deletions(-) rename source/extensions/dynamic_modules/sdk/go/abi/{internal.go => http.go} (82%) create mode 100644 source/extensions/dynamic_modules/sdk/go/abi/scheduler.go delete mode 100644 source/extensions/dynamic_modules/sdk/go/shared/api.go rename source/extensions/dynamic_modules/sdk/go/shared/fake/{fake_stream_base.go => fake_http.go} (95%) rename source/extensions/dynamic_modules/sdk/go/shared/fake/{fake_stream_base_test.go => fake_http_test.go} (100%) rename source/extensions/dynamic_modules/sdk/go/shared/{base.go => http.go} (51%) delete mode 100644 source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_api.go rename source/extensions/dynamic_modules/sdk/go/shared/mocks/{mock_base.go => mock_http.go} (88%) create mode 100644 source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_network_api.go create mode 100644 source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_network_base.go create mode 100644 source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_types.go create mode 100644 source/extensions/dynamic_modules/sdk/go/shared/types.go create mode 100644 test/extensions/dynamic_modules/test_data/go/http_stream_callouts_test/http_stream_callouts_test.go diff --git a/source/extensions/dynamic_modules/BUILD b/source/extensions/dynamic_modules/BUILD index 7c5922745b797..fe21c4aebac1b 100644 --- a/source/extensions/dynamic_modules/BUILD +++ b/source/extensions/dynamic_modules/BUILD @@ -49,23 +49,56 @@ envoy_cc_library( alwayslink = True, ) +# A meta-target that aggregates every per-surface abi_impl-style C++ library that +# implements the `envoy_dynamic_module_callback_*` host callbacks. +# +# The Go SDK's `abi/*.go` package is monolithic — importing it pulls in references to +# every surface's callbacks. So a Go test_data .so always references all of them. Tests +# that load such .so files must provide all of those symbols in the test binary's +# symbol table; otherwise dlopen's RTLD_LAZY can't resolve them and load fails. This +# meta-target lets a test depend on a single line and get every callback the Go SDK +# may have referenced. +envoy_cc_library( + name = "all_abi_impls", + deps = [ + ":abi_impl", + "//source/extensions/access_loggers/dynamic_modules:access_log_lib", + "//source/extensions/bootstrap/dynamic_modules:abi_impl", + "//source/extensions/clusters/dynamic_modules:cluster_lib", + "//source/extensions/filters/http/dynamic_modules:abi_impl", + "//source/extensions/filters/http/dynamic_modules:filter_lib", + "//source/extensions/filters/listener/dynamic_modules:filter_lib", + "//source/extensions/filters/network/dynamic_modules:filter_lib", + "//source/extensions/filters/udp/dynamic_modules:filter_lib", + "//source/extensions/load_balancing_policies/dynamic_modules:abi_impl", + "//source/extensions/matching/input_matchers/dynamic_modules:matcher_lib", + "//source/extensions/tracers/dynamic_modules:abi_impl", + "//source/extensions/transport_sockets/tls/cert_validator/dynamic_modules:config", + "//source/extensions/upstreams/http/dynamic_modules:abi_impl", + ], + alwayslink = True, +) + +# The shared package is pure Go (no cgo) — interfaces, types, and EmptyXxx no-ops shared +# across the SDK and module code. Modules depend on this transitively via go_sdk and +# go_sdk_abi. go_library( name = "go_sdk_shared", srcs = [ - "sdk/go/shared/api.go", - "sdk/go/shared/base.go", + "sdk/go/shared/http.go", "sdk/go/shared/network_api.go", "sdk/go/shared/network_base.go", + "sdk/go/shared/types.go", ], - cgo = True, importpath = "github.com/envoyproxy/envoy/source/extensions/dynamic_modules/sdk/go/shared", visibility = ["//visibility:public"], ) +# The top-level sdk package — pure Go. Holds the factory registries and program-handle +# indirection. Imports shared. go_library( name = "go_sdk", srcs = ["sdk/go/sdk.go"], - cgo = True, importpath = "github.com/envoyproxy/envoy/source/extensions/dynamic_modules/sdk/go", visibility = ["//visibility:public"], deps = [ @@ -73,11 +106,14 @@ go_library( ], ) +# The abi package — cgo-heavy. Implements the C-callable trampolines that Envoy invokes +# and the Go-callable wrappers that bridge into Envoy's host callbacks. go_library( name = "go_sdk_abi", srcs = [ - "sdk/go/abi/internal.go", + "sdk/go/abi/http.go", "sdk/go/abi/network.go", + "sdk/go/abi/scheduler.go", "//source/extensions/dynamic_modules/abi:abi.h", ], cgo = True, diff --git a/source/extensions/dynamic_modules/sdk/go/abi/internal.go b/source/extensions/dynamic_modules/sdk/go/abi/http.go similarity index 82% rename from source/extensions/dynamic_modules/sdk/go/abi/internal.go rename to source/extensions/dynamic_modules/sdk/go/abi/http.go index d0dd58b972607..b5d63c3fd92f8 100644 --- a/source/extensions/dynamic_modules/sdk/go/abi/internal.go +++ b/source/extensions/dynamic_modules/sdk/go/abi/http.go @@ -2,6 +2,7 @@ package abi /* #cgo darwin LDFLAGS: -Wl,-undefined,dynamic_lookup +#cgo linux LDFLAGS: -Wl,--unresolved-symbols=ignore-all #include #include #include @@ -15,7 +16,6 @@ import ( _ "embed" "fmt" "runtime" - "strconv" "sync" "unsafe" @@ -32,12 +32,6 @@ type httpFilterConfigWrapperPerRoute struct { config any } -type httpFilterWrapper = dymHttpFilterHandle - -type httpFilterSharedDataWrapper struct { - data any -} - const numManagerShards = 32 // The managers to keep track of configs and plugins. @@ -51,16 +45,19 @@ func (m *manager[T]) record(item *T) unsafe.Pointer { index := uintptr(pointer) % numManagerShards m.mutex[index].Lock() defer m.mutex[index].Unlock() - // Assume the map is initialized. m.data[index][uintptr(pointer)] = item return pointer } +// unwrap returns the live wrapper for the given pointer key, or nil if the wrapper is no +// longer registered (e.g., remove already ran). Callers MUST handle a nil return — a stale +// pointer cast would otherwise alias freed memory and crash or corrupt unrelated state when +// Envoy delivers a late callback after destroy. func (m *manager[T]) unwrap(itemPtr unsafe.Pointer) *T { - return (*T)(itemPtr) -} - -func (m *manager[T]) search(key uintptr) *T { + if itemPtr == nil { + return nil + } + key := uintptr(itemPtr) index := key % numManagerShards m.mutex[index].Lock() defer m.mutex[index].Unlock() @@ -84,8 +81,7 @@ func newManager[T any]() *manager[T] { var configManager = newManager[httpFilterConfigWrapper]() var configPerRouteManager = newManager[httpFilterConfigWrapperPerRoute]() -var pluginManager = newManager[httpFilterWrapper]() -var sharedDataManager = newManager[httpFilterSharedDataWrapper]() +var pluginManager = newManager[dymHttpFilterHandle]() //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -145,6 +141,28 @@ func envoyBufferToBytesUnsafe(buf C.envoy_dynamic_module_type_envoy_buffer) []by return unsafe.Slice((*byte)(unsafe.Pointer(buf.ptr)), buf.length) } +// envoyBufferToBytesCopy returns a Go-owned copy of the bytes in the Envoy-owned buffer. +// Use this whenever the bytes will be handed to user code that may retain them past the +// current cgo call (e.g., factory Create methods that store raw config). Adds a single +// allocation + memcpy; appropriate for config-time paths but not for data-path hot loops. +func envoyBufferToBytesCopy(buf C.envoy_dynamic_module_type_envoy_buffer) []byte { + if buf.ptr == nil || buf.length == 0 { + return nil + } + out := make([]byte, buf.length) + copy(out, unsafe.Slice((*byte)(unsafe.Pointer(buf.ptr)), buf.length)) + return out +} + +// envoyBufferToStringCopy returns a Go-owned copy of the bytes as a string. Same lifetime +// concerns as envoyBufferToBytesCopy. +func envoyBufferToStringCopy(buf C.envoy_dynamic_module_type_envoy_buffer) string { + if buf.ptr == nil || buf.length == 0 { + return "" + } + return string(unsafe.Slice((*byte)(unsafe.Pointer(buf.ptr)), buf.length)) +} + func envoyBufferToUnsafeEnvoyBuffer(buf C.envoy_dynamic_module_type_envoy_buffer) shared.UnsafeEnvoyBuffer { return shared.UnsafeEnvoyBuffer{ Ptr: (*byte)(unsafe.Pointer(buf.ptr)), @@ -348,194 +366,6 @@ func (b *dymBodyBuffer) Drain(size uint64) { ) } -type dymScheduler struct { - schedulerPtr unsafe.Pointer - schedulerLock sync.Mutex - nextTaskID uint64 - tasks map[uint64]func() - commitFunc func(unsafe.Pointer, C.uint64_t) -} - -func newDymScheduler( - schedulerPtr unsafe.Pointer, - commitFunc func(unsafe.Pointer, C.uint64_t), -) *dymScheduler { - return &dymScheduler{ - schedulerPtr: schedulerPtr, - tasks: make(map[uint64]func()), - commitFunc: commitFunc, - } -} - -func (s *dymScheduler) Schedule(task func()) { - // Lock the scheduler to prevent concurrent access - s.schedulerLock.Lock() - taskID := s.nextTaskID - s.nextTaskID++ - s.tasks[taskID] = task - s.schedulerLock.Unlock() - - // Call the host to schedule the task, passing the task ID as context - s.commitFunc(s.schedulerPtr, C.uint64_t(taskID)) -} - -func (s *dymScheduler) onScheduled(taskID uint64) { - s.schedulerLock.Lock() - task := s.tasks[taskID] - delete(s.tasks, taskID) - s.schedulerLock.Unlock() - if task != nil { - task() - } -} - -type dymSpan struct { - hostPluginPtr C.envoy_dynamic_module_type_http_filter_envoy_ptr - spanPtr C.envoy_dynamic_module_type_span_envoy_ptr -} - -func (s *dymSpan) SetTag(key, value string) { - if s == nil || s.spanPtr == nil { - return - } - C.envoy_dynamic_module_callback_http_span_set_tag( - s.spanPtr, - stringToModuleBuffer(key), - stringToModuleBuffer(value), - ) - runtime.KeepAlive(key) - runtime.KeepAlive(value) -} - -func (s *dymSpan) SetOperation(operation string) { - if s == nil || s.spanPtr == nil { - return - } - C.envoy_dynamic_module_callback_http_span_set_operation( - s.spanPtr, - stringToModuleBuffer(operation), - ) - runtime.KeepAlive(operation) -} - -func (s *dymSpan) Log(event string) { - if s == nil || s.spanPtr == nil { - return - } - C.envoy_dynamic_module_callback_http_span_log( - s.hostPluginPtr, - s.spanPtr, - stringToModuleBuffer(event), - ) - runtime.KeepAlive(event) -} - -func (s *dymSpan) SetSampled(sampled bool) { - if s == nil || s.spanPtr == nil { - return - } - C.envoy_dynamic_module_callback_http_span_set_sampled(s.spanPtr, C.bool(sampled)) -} - -func (s *dymSpan) GetBaggage(key string) (shared.UnsafeEnvoyBuffer, bool) { - if s == nil || s.spanPtr == nil { - return shared.UnsafeEnvoyBuffer{}, false - } - var valueView C.envoy_dynamic_module_type_envoy_buffer - ret := C.envoy_dynamic_module_callback_http_span_get_baggage( - s.spanPtr, - stringToModuleBuffer(key), - &valueView, - ) - runtime.KeepAlive(key) - if !bool(ret) { - return shared.UnsafeEnvoyBuffer{}, false - } - if valueView.ptr == nil || valueView.length == 0 { - return shared.UnsafeEnvoyBuffer{}, true - } - return envoyBufferToUnsafeEnvoyBuffer(valueView), true -} - -func (s *dymSpan) SetBaggage(key, value string) { - if s == nil || s.spanPtr == nil { - return - } - C.envoy_dynamic_module_callback_http_span_set_baggage( - s.spanPtr, - stringToModuleBuffer(key), - stringToModuleBuffer(value), - ) - runtime.KeepAlive(key) - runtime.KeepAlive(value) -} - -func (s *dymSpan) GetTraceID() (shared.UnsafeEnvoyBuffer, bool) { - if s == nil || s.spanPtr == nil { - return shared.UnsafeEnvoyBuffer{}, false - } - var valueView C.envoy_dynamic_module_type_envoy_buffer - ret := C.envoy_dynamic_module_callback_http_span_get_trace_id(s.spanPtr, &valueView) - if !bool(ret) { - return shared.UnsafeEnvoyBuffer{}, false - } - if valueView.ptr == nil || valueView.length == 0 { - return shared.UnsafeEnvoyBuffer{}, true - } - return envoyBufferToUnsafeEnvoyBuffer(valueView), true -} - -func (s *dymSpan) GetSpanID() (shared.UnsafeEnvoyBuffer, bool) { - if s == nil || s.spanPtr == nil { - return shared.UnsafeEnvoyBuffer{}, false - } - var valueView C.envoy_dynamic_module_type_envoy_buffer - ret := C.envoy_dynamic_module_callback_http_span_get_span_id(s.spanPtr, &valueView) - if !bool(ret) { - return shared.UnsafeEnvoyBuffer{}, false - } - if valueView.ptr == nil || valueView.length == 0 { - return shared.UnsafeEnvoyBuffer{}, true - } - return envoyBufferToUnsafeEnvoyBuffer(valueView), true -} - -func (s *dymSpan) SpawnChild(operation string) shared.ChildSpan { - if s == nil || s.spanPtr == nil { - return nil - } - childPtr := C.envoy_dynamic_module_callback_http_span_spawn_child( - s.hostPluginPtr, - s.spanPtr, - stringToModuleBuffer(operation), - ) - runtime.KeepAlive(operation) - if childPtr == nil { - return nil - } - return &dymChildSpan{ - dymSpan: dymSpan{ - hostPluginPtr: s.hostPluginPtr, - spanPtr: C.envoy_dynamic_module_type_span_envoy_ptr(childPtr), - }, - childPtr: childPtr, - } -} - -type dymChildSpan struct { - dymSpan - childPtr C.envoy_dynamic_module_type_child_span_module_ptr -} - -func (s *dymChildSpan) Finish() { - if s == nil || s.childPtr == nil { - return - } - C.envoy_dynamic_module_callback_http_child_span_finish(s.childPtr) - s.childPtr = nil - s.spanPtr = nil -} - type dymHttpFilterHandle struct { hostPluginPtr C.envoy_dynamic_module_type_http_filter_envoy_ptr @@ -551,16 +381,77 @@ type dymHttpFilterHandle struct { plugin shared.HttpFilter scheduler *dymScheduler streamCompleted bool - streamDestoried bool + streamDestroyed bool localResponseSent bool // nextCalloutID was removed because callout ID is now returned by the host. + // calloutMu guards calloutCallbacks and streamCallbacks. Per-stream HTTP filter + // processing is single-threaded today, so this lock is uncontended in normal use; it's + // held to match the cluster/bootstrap callout maps and to keep the SDK safe if a future + // change introduces cross-thread callout dispatch. + calloutMu sync.Mutex calloutCallbacks map[uint64]shared.HttpCalloutCallback streamCallbacks map[uint64]shared.HttpStreamCallback - recordedSharedData []unsafe.Pointer + // data backs SetData/GetData — per-stream module-private state for cross-phase + // communication. Held in Go memory rather than smuggled through Envoy dynamic metadata + // (which would expose the storage to other filters and observers). + dataMu sync.Mutex + data map[string]any downstreamWatermarkCallbacks shared.DownstreamWatermarkCallbacks + + // childSpans tracks unfinished child spans owned by user code so they can be marked + // as finished (without dispatching to Envoy) when the parent stream is destroyed. + // Without this, a finalizer-driven Finish() after stream destroy would invoke + // envoy_dynamic_module_callback_http_child_span_finish against a freed span pointer. + childSpansMu sync.Mutex + childSpans map[*dymChildSpan]struct{} +} + +// trackChildSpan registers a child span so it will be safely retired if the stream is +// destroyed before the module calls Finish on it. +func (h *dymHttpFilterHandle) trackChildSpan(c *dymChildSpan) { + h.childSpansMu.Lock() + if h.streamDestroyed { + // Stream is already gone. Mark the child as finished without dispatching to Envoy + // and skip finalizer registration. + h.childSpansMu.Unlock() + c.finishedMu.Lock() + c.finished = true + c.finishedMu.Unlock() + return + } + if h.childSpans == nil { + h.childSpans = make(map[*dymChildSpan]struct{}) + } + h.childSpans[c] = struct{}{} + h.childSpansMu.Unlock() + runtime.SetFinalizer(c, func(c *dymChildSpan) { c.Finish() }) +} + +// untrackChildSpan removes a child span from the wrapper's tracking set after the user +// calls Finish on it. +func (h *dymHttpFilterHandle) untrackChildSpan(c *dymChildSpan) { + h.childSpansMu.Lock() + delete(h.childSpans, c) + h.childSpansMu.Unlock() +} + +// retireChildSpansOnDestroy is called from the stream-destroy hook. It marks every +// unfinished child span as finished (so the finalizer, if any, becomes a no-op) and +// clears the finalizer to release the GC anchor. +func (h *dymHttpFilterHandle) retireChildSpansOnDestroy() { + h.childSpansMu.Lock() + spans := h.childSpans + h.childSpans = nil + h.childSpansMu.Unlock() + for c := range spans { + c.finishedMu.Lock() + c.finished = true + c.finishedMu.Unlock() + runtime.SetFinalizer(c, nil) + } } func (h *dymHttpFilterHandle) GetMetadataString(source shared.MetadataSourceType, metadataNamespace, key string) (shared.UnsafeEnvoyBuffer, bool) { @@ -862,7 +753,7 @@ func (h *dymHttpFilterHandle) SetMetadata(metadataNamespace, key string, value a func (h *dymHttpFilterHandle) GetAttributeNumber( attributeID shared.AttributeID, -) (float64, bool) { +) (uint64, bool) { var value C.uint64_t = 0 ret := C.envoy_dynamic_module_callback_http_filter_get_attribute_int( @@ -874,7 +765,7 @@ func (h *dymHttpFilterHandle) GetAttributeNumber( return 0, false } - return float64(value), true + return uint64(value), true } func (h *dymHttpFilterHandle) GetAttributeString( @@ -911,24 +802,6 @@ func (h *dymHttpFilterHandle) GetAttributeBool( return bool(value), true } -func (h *dymHttpFilterHandle) GetFilterStateTyped(key string) (shared.UnsafeEnvoyBuffer, bool) { - var valueView C.envoy_dynamic_module_type_envoy_buffer - - ret := C.envoy_dynamic_module_callback_http_get_filter_state_typed( - h.hostPluginPtr, - stringToModuleBuffer(key), - &valueView, - ) - runtime.KeepAlive(key) - if !bool(ret) { - return shared.UnsafeEnvoyBuffer{}, false - } - if valueView.ptr == nil || valueView.length == 0 { - return shared.UnsafeEnvoyBuffer{}, true - } - return envoyBufferToUnsafeEnvoyBuffer(valueView), true -} - func (h *dymHttpFilterHandle) GetFilterState(key string) (shared.UnsafeEnvoyBuffer, bool) { var valueView C.envoy_dynamic_module_type_envoy_buffer @@ -955,52 +828,22 @@ func (h *dymHttpFilterHandle) SetFilterState(key string, value []byte) { runtime.KeepAlive(value) } -func (h *dymHttpFilterHandle) SetFilterStateTyped(key string, value []byte) bool { - ret := C.envoy_dynamic_module_callback_http_set_filter_state_typed( - h.hostPluginPtr, - stringToModuleBuffer(key), - bytesToModuleBuffer(value), - ) - runtime.KeepAlive(key) - runtime.KeepAlive(value) - return bool(ret) -} - func (h *dymHttpFilterHandle) GetData(key string) any { - buf, found := h.GetMetadataString(shared.MetadataSourceTypeDynamic, - "composer.shared_data", key) - if !found { - return nil - } - // Convert string back to uintptr safely. - uintValue, err := strconv.ParseUint(buf.ToUnsafeString(), 10, 64) - if err != nil { - return nil - } - pointer := uintptr(uintValue) - // Use search rather than unwrap because the go runtime will complain - // the pointer parsed from string `pointer arithmetic result points to invalid allocation`. - wrapper := sharedDataManager.search(pointer) - if wrapper == nil { + h.dataMu.Lock() + defer h.dataMu.Unlock() + if h.data == nil { return nil } - return wrapper.data + return h.data[key] } func (h *dymHttpFilterHandle) SetData(key string, value any) { - wrapper := &httpFilterSharedDataWrapper{data: value} - pointer := sharedDataManager.record(wrapper) - h.recordedSharedData = append(h.recordedSharedData, pointer) - - // Covert pointer to uintptr to string safely. - stringValue := strconv.FormatUint(uint64(uintptr(pointer)), 10) - h.SetMetadata("composer.shared_data", key, stringValue) -} - -func (h *dymHttpFilterHandle) clearData() { - for _, pointer := range h.recordedSharedData { - sharedDataManager.remove(pointer) + h.dataMu.Lock() + defer h.dataMu.Unlock() + if h.data == nil { + h.data = make(map[string]any) } + h.data[key] = value } func (h *dymHttpFilterHandle) SendLocalResponse( @@ -1094,204 +937,32 @@ func (h *dymHttpFilterHandle) RefreshRouteCluster() { C.envoy_dynamic_module_callback_http_clear_route_cluster_cache(h.hostPluginPtr) } -func (h *dymHttpFilterHandle) GetWorkerIndex() uint32 { - return uint32(C.envoy_dynamic_module_callback_http_filter_get_worker_index(h.hostPluginPtr)) +func (h *dymHttpFilterHandle) RequestHeaders() shared.HeaderMap { + return &h.requestHeaderMap } -func (h *dymHttpFilterHandle) SetSocketOptionInt( - level, name int64, - state shared.SocketOptionState, - direction shared.SocketDirection, - value int64, -) bool { - ret := C.envoy_dynamic_module_callback_http_set_socket_option_int( - h.hostPluginPtr, - C.int64_t(level), - C.int64_t(name), - C.envoy_dynamic_module_type_socket_option_state(state), - C.envoy_dynamic_module_type_socket_direction(direction), - C.int64_t(value), - ) - return bool(ret) +func (h *dymHttpFilterHandle) BufferedRequestBody() shared.BodyBuffer { + return &h.bufferedRequestBody } -func (h *dymHttpFilterHandle) SetSocketOptionBytes( - level, name int64, - state shared.SocketOptionState, - direction shared.SocketDirection, - value []byte, -) bool { - ret := C.envoy_dynamic_module_callback_http_set_socket_option_bytes( - h.hostPluginPtr, - C.int64_t(level), - C.int64_t(name), - C.envoy_dynamic_module_type_socket_option_state(state), - C.envoy_dynamic_module_type_socket_direction(direction), - bytesToModuleBuffer(value), - ) - runtime.KeepAlive(value) - return bool(ret) +func (h *dymHttpFilterHandle) ReceivedRequestBody() shared.BodyBuffer { + return &h.receivedRequestBody } -func (h *dymHttpFilterHandle) GetSocketOptionInt( - level, name int64, - state shared.SocketOptionState, - direction shared.SocketDirection, -) (int64, bool) { - var value C.int64_t - ret := C.envoy_dynamic_module_callback_http_get_socket_option_int( - h.hostPluginPtr, - C.int64_t(level), - C.int64_t(name), - C.envoy_dynamic_module_type_socket_option_state(state), - C.envoy_dynamic_module_type_socket_direction(direction), - &value, - ) - if !bool(ret) { - return 0, false - } - return int64(value), true +func (h *dymHttpFilterHandle) RequestTrailers() shared.HeaderMap { + return &h.requestTrailerMap } -func (h *dymHttpFilterHandle) GetSocketOptionBytes( - level, name int64, - state shared.SocketOptionState, - direction shared.SocketDirection, -) (shared.UnsafeEnvoyBuffer, bool) { - var valueView C.envoy_dynamic_module_type_envoy_buffer - ret := C.envoy_dynamic_module_callback_http_get_socket_option_bytes( - h.hostPluginPtr, - C.int64_t(level), - C.int64_t(name), - C.envoy_dynamic_module_type_socket_option_state(state), - C.envoy_dynamic_module_type_socket_direction(direction), - &valueView, - ) - if !bool(ret) { - return shared.UnsafeEnvoyBuffer{}, false - } - if valueView.ptr == nil || valueView.length == 0 { - return shared.UnsafeEnvoyBuffer{}, true - } - return envoyBufferToUnsafeEnvoyBuffer(valueView), true +func (h *dymHttpFilterHandle) ResponseHeaders() shared.HeaderMap { + return &h.responseHeaderMap } -func (h *dymHttpFilterHandle) GetBufferLimit() uint64 { - return uint64(C.envoy_dynamic_module_callback_http_get_buffer_limit(h.hostPluginPtr)) +func (h *dymHttpFilterHandle) BufferedResponseBody() shared.BodyBuffer { + return &h.bufferedResponseBody } -func (h *dymHttpFilterHandle) SetBufferLimit(limit uint64) { - C.envoy_dynamic_module_callback_http_set_buffer_limit(h.hostPluginPtr, C.uint64_t(limit)) -} - -func (h *dymHttpFilterHandle) GetActiveSpan() shared.Span { - spanPtr := C.envoy_dynamic_module_callback_http_get_active_span(h.hostPluginPtr) - if spanPtr == nil { - return nil - } - return &dymSpan{ - hostPluginPtr: h.hostPluginPtr, - spanPtr: spanPtr, - } -} - -func (h *dymHttpFilterHandle) GetClusterName() (shared.UnsafeEnvoyBuffer, bool) { - var valueView C.envoy_dynamic_module_type_envoy_buffer - ret := C.envoy_dynamic_module_callback_http_get_cluster_name(h.hostPluginPtr, &valueView) - if !bool(ret) { - return shared.UnsafeEnvoyBuffer{}, false - } - if valueView.ptr == nil || valueView.length == 0 { - return shared.UnsafeEnvoyBuffer{}, true - } - return envoyBufferToUnsafeEnvoyBuffer(valueView), true -} - -func (h *dymHttpFilterHandle) GetClusterHostCounts(priority uint32) (shared.ClusterHostCounts, bool) { - var total C.size_t - var healthy C.size_t - var degraded C.size_t - ret := C.envoy_dynamic_module_callback_http_get_cluster_host_count( - h.hostPluginPtr, - C.uint32_t(priority), - &total, - &healthy, - °raded, - ) - if !bool(ret) { - return shared.ClusterHostCounts{}, false - } - return shared.ClusterHostCounts{ - Total: uint64(total), - Healthy: uint64(healthy), - Degraded: uint64(degraded), - }, true -} - -func (h *dymHttpFilterHandle) SetUpstreamOverrideHost(host string, strict bool) bool { - ret := C.envoy_dynamic_module_callback_http_set_upstream_override_host( - h.hostPluginPtr, - stringToModuleBuffer(host), - C.bool(strict), - ) - runtime.KeepAlive(host) - return bool(ret) -} - -func (h *dymHttpFilterHandle) ResetStream(reason shared.HttpFilterStreamResetReason, details string) { - C.envoy_dynamic_module_callback_http_filter_reset_stream( - h.hostPluginPtr, - C.envoy_dynamic_module_type_http_filter_stream_reset_reason(reason), - stringToModuleBuffer(details), - ) - runtime.KeepAlive(details) -} - -func (h *dymHttpFilterHandle) SendGoAwayAndClose(graceful bool) { - C.envoy_dynamic_module_callback_http_filter_send_go_away_and_close( - h.hostPluginPtr, - C.bool(graceful), - ) -} - -func (h *dymHttpFilterHandle) RecreateStream(headers [][2]string) bool { - headerViews := headersToModuleHttpHeaderSlice(headers) - ret := C.envoy_dynamic_module_callback_http_filter_recreate_stream( - h.hostPluginPtr, - unsafe.SliceData(headerViews), - C.size_t(len(headerViews)), - ) - runtime.KeepAlive(headers) - runtime.KeepAlive(headerViews) - return bool(ret) -} - -func (h *dymHttpFilterHandle) RequestHeaders() shared.HeaderMap { - return &h.requestHeaderMap -} - -func (h *dymHttpFilterHandle) BufferedRequestBody() shared.BodyBuffer { - return &h.bufferedRequestBody -} - -func (h *dymHttpFilterHandle) ReceivedRequestBody() shared.BodyBuffer { - return &h.receivedRequestBody -} - -func (h *dymHttpFilterHandle) RequestTrailers() shared.HeaderMap { - return &h.requestTrailerMap -} - -func (h *dymHttpFilterHandle) ResponseHeaders() shared.HeaderMap { - return &h.responseHeaderMap -} - -func (h *dymHttpFilterHandle) BufferedResponseBody() shared.BodyBuffer { - return &h.bufferedResponseBody -} - -func (h *dymHttpFilterHandle) ReceivedResponseBody() shared.BodyBuffer { - return &h.receivedResponseBody +func (h *dymHttpFilterHandle) ReceivedResponseBody() shared.BodyBuffer { + return &h.receivedResponseBody } func (h *dymHttpFilterHandle) ReceivedBufferedRequestBody() bool { @@ -1335,13 +1006,18 @@ func (h *dymHttpFilterHandle) GetScheduler() shared.Scheduler { taskID, ) }, + func(p unsafe.Pointer) { + C.envoy_dynamic_module_callback_http_filter_scheduler_delete( + (C.envoy_dynamic_module_type_http_filter_scheduler_module_ptr)(p), + ) + }, ) - runtime.SetFinalizer(h.scheduler, func(s *dymScheduler) { - C.envoy_dynamic_module_callback_http_filter_scheduler_delete( - (C.envoy_dynamic_module_type_http_filter_scheduler_module_ptr)(s.schedulerPtr), - ) - }) + // Finalizer is a fallback for the case where the host never invokes the destroy + // hook (e.g., embedded use cases). The synchronous close() in the destroy hook is + // the primary path; once close() runs, schedulerPtr is nil and the finalizer is + // a no-op. + runtime.SetFinalizer(h.scheduler, func(s *dymScheduler) { s.close() }) } return h.scheduler } @@ -1377,10 +1053,12 @@ func (h *dymHttpFilterHandle) HttpCallout( return goResult, 0 } + h.calloutMu.Lock() if h.calloutCallbacks == nil { h.calloutCallbacks = make(map[uint64]shared.HttpCalloutCallback) } h.calloutCallbacks[uint64(calloutID)] = cb + h.calloutMu.Unlock() return goResult, uint64(calloutID) } @@ -1394,165 +1072,591 @@ func (h *dymHttpFilterHandle) StartHttpStream( result := C.envoy_dynamic_module_callback_http_filter_start_http_stream( h.hostPluginPtr, - &streamID, - stringToModuleBuffer(cluster), + &streamID, + stringToModuleBuffer(cluster), + unsafe.SliceData(headerViews), + (C.size_t)(len(headerViews)), + bytesToModuleBuffer(body), + (C.bool)(endOfStream), + (C.uint64_t)(timeoutMs), + ) + + runtime.KeepAlive(cluster) + runtime.KeepAlive(headers) + runtime.KeepAlive(body) + runtime.KeepAlive(headerViews) + + goResult := shared.HttpCalloutInitResult(result) + if goResult != shared.HttpCalloutInitSuccess { + return goResult, 0 + } + + h.calloutMu.Lock() + if h.streamCallbacks == nil { + h.streamCallbacks = make(map[uint64]shared.HttpStreamCallback) + } + h.streamCallbacks[uint64(streamID)] = cb + h.calloutMu.Unlock() + + return goResult, uint64(streamID) +} + +func (h *dymHttpFilterHandle) SendHttpStreamData( + streamID uint64, data []byte, endOfStream bool, +) bool { + ret := C.envoy_dynamic_module_callback_http_stream_send_data( + h.hostPluginPtr, + (C.uint64_t)(streamID), + bytesToModuleBuffer(data), + (C.bool)(endOfStream), + ) + runtime.KeepAlive(data) + return bool(ret) +} + +func (h *dymHttpFilterHandle) SendHttpStreamTrailers( + streamID uint64, trailers [][2]string, +) bool { + // Prepare trailers. + trailerViews := headersToModuleHttpHeaderSlice(trailers) + ret := C.envoy_dynamic_module_callback_http_stream_send_trailers( + h.hostPluginPtr, + (C.uint64_t)(streamID), + unsafe.SliceData(trailerViews), + (C.size_t)(len(trailerViews)), + ) + runtime.KeepAlive(trailers) + runtime.KeepAlive(trailerViews) + return bool(ret) +} + +func (h *dymHttpFilterHandle) ResetHttpStream( + streamID uint64, +) { + C.envoy_dynamic_module_callback_http_filter_reset_http_stream( + h.hostPluginPtr, + (C.uint64_t)(streamID), + ) +} + +func (h *dymHttpFilterHandle) SetDownstreamWatermarkCallbacks( + cbs shared.DownstreamWatermarkCallbacks, +) { + h.downstreamWatermarkCallbacks = cbs +} + +func (h *dymHttpFilterHandle) ClearDownstreamWatermarkCallbacks() { + h.downstreamWatermarkCallbacks = nil +} + +func (h *dymHttpFilterHandle) RecordHistogramValue(id shared.MetricID, + value uint64, tagsValues ...string) shared.MetricsResult { + idUint64 := uint64(id) + // Prepare tag values. + tagValueViews := stringArrayToModuleBufferSlice(tagsValues) + + ret := C.envoy_dynamic_module_callback_http_filter_record_histogram_value( + h.hostPluginPtr, + (C.size_t)(idUint64), + unsafe.SliceData(tagValueViews), + (C.size_t)(len(tagValueViews)), + (C.uint64_t)(value), + ) + + runtime.KeepAlive(tagsValues) + runtime.KeepAlive(tagValueViews) + return shared.MetricsResult(ret) +} + +func (h *dymHttpFilterHandle) SetGaugeValue(id shared.MetricID, + value uint64, tagsValues ...string) shared.MetricsResult { + idUint64 := uint64(id) + // Prepare tag values. + tagValueViews := stringArrayToModuleBufferSlice(tagsValues) + + ret := C.envoy_dynamic_module_callback_http_filter_set_gauge( + h.hostPluginPtr, + (C.size_t)(idUint64), + unsafe.SliceData(tagValueViews), + (C.size_t)(len(tagValueViews)), + (C.uint64_t)(value), + ) + + runtime.KeepAlive(tagsValues) + runtime.KeepAlive(tagValueViews) + return shared.MetricsResult(ret) +} + +func (h *dymHttpFilterHandle) IncrementGaugeValue(id shared.MetricID, + value uint64, tagsValues ...string) shared.MetricsResult { + // Prepare tag values. + tagValueViews := stringArrayToModuleBufferSlice(tagsValues) + ret := C.envoy_dynamic_module_callback_http_filter_increment_gauge( + h.hostPluginPtr, + (C.size_t)(uint64(id)), + unsafe.SliceData(tagValueViews), + (C.size_t)(len(tagValueViews)), + (C.uint64_t)(value), + ) + runtime.KeepAlive(tagsValues) + runtime.KeepAlive(tagValueViews) + return shared.MetricsResult(ret) +} + +func (h *dymHttpFilterHandle) DecrementGaugeValue(id shared.MetricID, + value uint64, tagsValues ...string) shared.MetricsResult { + // Prepare tag values. + tagValueViews := stringArrayToModuleBufferSlice(tagsValues) + ret := C.envoy_dynamic_module_callback_http_filter_decrement_gauge( + h.hostPluginPtr, + (C.size_t)(uint64(id)), + unsafe.SliceData(tagValueViews), + (C.size_t)(len(tagValueViews)), + (C.uint64_t)(value), + ) + runtime.KeepAlive(tagsValues) + runtime.KeepAlive(tagValueViews) + return shared.MetricsResult(ret) +} + +func (h *dymHttpFilterHandle) IncrementCounterValue(id shared.MetricID, + value uint64, tagsValues ...string) shared.MetricsResult { + // Prepare tag values. + tagValueViews := stringArrayToModuleBufferSlice(tagsValues) + ret := C.envoy_dynamic_module_callback_http_filter_increment_counter( + h.hostPluginPtr, + (C.size_t)(uint64(id)), + unsafe.SliceData(tagValueViews), + (C.size_t)(len(tagValueViews)), + (C.uint64_t)(value), + ) + runtime.KeepAlive(tagsValues) + runtime.KeepAlive(tagValueViews) + return shared.MetricsResult(ret) +} + +func (h *dymHttpFilterHandle) GetWorkerIndex() uint32 { + return uint32(C.envoy_dynamic_module_callback_http_filter_get_worker_index( + h.hostPluginPtr, + )) +} + +func (h *dymHttpFilterHandle) GetFilterStateTyped(key string) (shared.UnsafeEnvoyBuffer, bool) { + var valueView C.envoy_dynamic_module_type_envoy_buffer + + ret := C.envoy_dynamic_module_callback_http_get_filter_state_typed( + h.hostPluginPtr, + stringToModuleBuffer(key), + &valueView, + ) + runtime.KeepAlive(key) + if !bool(ret) || valueView.ptr == nil || valueView.length == 0 { + return shared.UnsafeEnvoyBuffer{}, bool(ret) + } + return envoyBufferToUnsafeEnvoyBuffer(valueView), true +} + +func (h *dymHttpFilterHandle) SetFilterStateTyped(key string, value []byte) bool { + ret := C.envoy_dynamic_module_callback_http_set_filter_state_typed( + h.hostPluginPtr, + stringToModuleBuffer(key), + bytesToModuleBuffer(value), + ) + runtime.KeepAlive(key) + runtime.KeepAlive(value) + return bool(ret) +} + +func (h *dymHttpFilterHandle) SetSocketOptionInt( + level, name int64, state shared.SocketOptionState, + direction shared.SocketDirection, value int64, +) bool { + return bool(C.envoy_dynamic_module_callback_http_set_socket_option_int( + h.hostPluginPtr, + (C.int64_t)(level), + (C.int64_t)(name), + (C.envoy_dynamic_module_type_socket_option_state)(state), + (C.envoy_dynamic_module_type_socket_direction)(direction), + (C.int64_t)(value), + )) +} + +func (h *dymHttpFilterHandle) SetSocketOptionBytes( + level, name int64, state shared.SocketOptionState, + direction shared.SocketDirection, value []byte, +) bool { + ret := C.envoy_dynamic_module_callback_http_set_socket_option_bytes( + h.hostPluginPtr, + (C.int64_t)(level), + (C.int64_t)(name), + (C.envoy_dynamic_module_type_socket_option_state)(state), + (C.envoy_dynamic_module_type_socket_direction)(direction), + bytesToModuleBuffer(value), + ) + runtime.KeepAlive(value) + return bool(ret) +} + +func (h *dymHttpFilterHandle) GetSocketOptionInt( + level, name int64, state shared.SocketOptionState, + direction shared.SocketDirection, +) (int64, bool) { + var value C.int64_t = 0 + ret := C.envoy_dynamic_module_callback_http_get_socket_option_int( + h.hostPluginPtr, + (C.int64_t)(level), + (C.int64_t)(name), + (C.envoy_dynamic_module_type_socket_option_state)(state), + (C.envoy_dynamic_module_type_socket_direction)(direction), + &value, + ) + if !bool(ret) { + return 0, false + } + return int64(value), true +} + +func (h *dymHttpFilterHandle) GetSocketOptionBytes( + level, name int64, state shared.SocketOptionState, + direction shared.SocketDirection, +) (shared.UnsafeEnvoyBuffer, bool) { + var valueView C.envoy_dynamic_module_type_envoy_buffer + ret := C.envoy_dynamic_module_callback_http_get_socket_option_bytes( + h.hostPluginPtr, + (C.int64_t)(level), + (C.int64_t)(name), + (C.envoy_dynamic_module_type_socket_option_state)(state), + (C.envoy_dynamic_module_type_socket_direction)(direction), + &valueView, + ) + if !bool(ret) || valueView.ptr == nil || valueView.length == 0 { + return shared.UnsafeEnvoyBuffer{}, bool(ret) + } + return envoyBufferToUnsafeEnvoyBuffer(valueView), true +} + +func (h *dymHttpFilterHandle) GetBufferLimit() uint64 { + return uint64(C.envoy_dynamic_module_callback_http_get_buffer_limit( + h.hostPluginPtr, + )) +} + +func (h *dymHttpFilterHandle) SetBufferLimit(limit uint64) { + C.envoy_dynamic_module_callback_http_set_buffer_limit( + h.hostPluginPtr, + (C.uint64_t)(limit), + ) +} + +func (h *dymHttpFilterHandle) GetActiveSpan() shared.Span { + spanPtr := C.envoy_dynamic_module_callback_http_get_active_span( + h.hostPluginPtr, + ) + if spanPtr == nil { + return nil + } + return &dymSpan{ + spanPtr: spanPtr, + hostPluginPtr: h.hostPluginPtr, + filter: h, + } +} + +func (h *dymHttpFilterHandle) GetClusterName() (shared.UnsafeEnvoyBuffer, bool) { + var valueView C.envoy_dynamic_module_type_envoy_buffer + ret := C.envoy_dynamic_module_callback_http_get_cluster_name( + h.hostPluginPtr, + &valueView, + ) + if !bool(ret) || valueView.ptr == nil || valueView.length == 0 { + return shared.UnsafeEnvoyBuffer{}, bool(ret) + } + return envoyBufferToUnsafeEnvoyBuffer(valueView), true +} + +func (h *dymHttpFilterHandle) GetClusterHostCounts(priority uint32) (shared.ClusterHostCounts, bool) { + var total, healthy, degraded C.size_t + ret := C.envoy_dynamic_module_callback_http_get_cluster_host_count( + h.hostPluginPtr, + (C.uint32_t)(priority), + &total, + &healthy, + °raded, + ) + if !bool(ret) { + return shared.ClusterHostCounts{}, false + } + return shared.ClusterHostCounts{ + Total: uint64(total), + Healthy: uint64(healthy), + Degraded: uint64(degraded), + }, true +} + +func (h *dymHttpFilterHandle) SetUpstreamOverrideHost(host string, strict bool) bool { + ret := C.envoy_dynamic_module_callback_http_set_upstream_override_host( + h.hostPluginPtr, + stringToModuleBuffer(host), + (C.bool)(strict), + ) + runtime.KeepAlive(host) + return bool(ret) +} + +func (h *dymHttpFilterHandle) ResetStream(reason shared.HttpFilterStreamResetReason, details string) { + C.envoy_dynamic_module_callback_http_filter_reset_stream( + h.hostPluginPtr, + (C.envoy_dynamic_module_type_http_filter_stream_reset_reason)(reason), + stringToModuleBuffer(details), + ) + runtime.KeepAlive(details) +} + +func (h *dymHttpFilterHandle) SendGoAwayAndClose(graceful bool) { + C.envoy_dynamic_module_callback_http_filter_send_go_away_and_close( + h.hostPluginPtr, + (C.bool)(graceful), + ) +} + +func (h *dymHttpFilterHandle) RecreateStream(headers [][2]string) bool { + if len(headers) == 0 { + return bool(C.envoy_dynamic_module_callback_http_filter_recreate_stream( + h.hostPluginPtr, + nil, + 0, + )) + } + headerViews := headersToModuleHttpHeaderSlice(headers) + ret := C.envoy_dynamic_module_callback_http_filter_recreate_stream( + h.hostPluginPtr, unsafe.SliceData(headerViews), (C.size_t)(len(headerViews)), - bytesToModuleBuffer(body), - (C.bool)(endOfStream), - (C.uint64_t)(timeoutMs), ) - - runtime.KeepAlive(cluster) runtime.KeepAlive(headers) - runtime.KeepAlive(body) runtime.KeepAlive(headerViews) + return bool(ret) +} - goResult := shared.HttpCalloutInitResult(result) - if goResult != shared.HttpCalloutInitSuccess { - return goResult, 0 - } +// dymSpan implements shared.Span by wrapping the active span pointer for the current stream. +// The pointer is owned by Envoy and must not be finished by the module. filter is retained so +// child spans spawned from this span can be tracked on the owning filter handle and safely +// retired when the stream is destroyed. +type dymSpan struct { + spanPtr C.envoy_dynamic_module_type_span_envoy_ptr + hostPluginPtr C.envoy_dynamic_module_type_http_filter_envoy_ptr + filter *dymHttpFilterHandle +} - if h.streamCallbacks == nil { - h.streamCallbacks = make(map[uint64]shared.HttpStreamCallback) - } - h.streamCallbacks[uint64(streamID)] = cb +func (s *dymSpan) SetTag(key, value string) { + C.envoy_dynamic_module_callback_http_span_set_tag( + s.spanPtr, + stringToModuleBuffer(key), + stringToModuleBuffer(value), + ) + runtime.KeepAlive(key) + runtime.KeepAlive(value) +} - return goResult, uint64(streamID) +func (s *dymSpan) SetOperation(operation string) { + C.envoy_dynamic_module_callback_http_span_set_operation( + s.spanPtr, + stringToModuleBuffer(operation), + ) + runtime.KeepAlive(operation) } -func (h *dymHttpFilterHandle) SendHttpStreamData( - streamID uint64, data []byte, endOfStream bool, -) bool { - ret := C.envoy_dynamic_module_callback_http_stream_send_data( - h.hostPluginPtr, - (C.uint64_t)(streamID), - bytesToModuleBuffer(data), - (C.bool)(endOfStream), +func (s *dymSpan) Log(event string) { + C.envoy_dynamic_module_callback_http_span_log( + s.hostPluginPtr, + s.spanPtr, + stringToModuleBuffer(event), ) - runtime.KeepAlive(data) - return bool(ret) + runtime.KeepAlive(event) } -func (h *dymHttpFilterHandle) SendHttpStreamTrailers( - streamID uint64, trailers [][2]string, -) bool { - // Prepare trailers. - trailerViews := headersToModuleHttpHeaderSlice(trailers) - ret := C.envoy_dynamic_module_callback_http_stream_send_trailers( - h.hostPluginPtr, - (C.uint64_t)(streamID), - unsafe.SliceData(trailerViews), - (C.size_t)(len(trailerViews)), +func (s *dymSpan) SetSampled(sampled bool) { + C.envoy_dynamic_module_callback_http_span_set_sampled( + s.spanPtr, + (C.bool)(sampled), ) - runtime.KeepAlive(trailers) - runtime.KeepAlive(trailerViews) - return bool(ret) } -func (h *dymHttpFilterHandle) ResetHttpStream( - streamID uint64, -) { - C.envoy_dynamic_module_callback_http_filter_reset_http_stream( - h.hostPluginPtr, - (C.uint64_t)(streamID), +func (s *dymSpan) GetBaggage(key string) (shared.UnsafeEnvoyBuffer, bool) { + var valueView C.envoy_dynamic_module_type_envoy_buffer + ret := C.envoy_dynamic_module_callback_http_span_get_baggage( + s.spanPtr, + stringToModuleBuffer(key), + &valueView, ) + runtime.KeepAlive(key) + if !bool(ret) || valueView.ptr == nil || valueView.length == 0 { + return shared.UnsafeEnvoyBuffer{}, bool(ret) + } + return envoyBufferToUnsafeEnvoyBuffer(valueView), true } -func (h *dymHttpFilterHandle) SetDownstreamWatermarkCallbacks( - cbs shared.DownstreamWatermarkCallbacks, -) { - h.downstreamWatermarkCallbacks = cbs +func (s *dymSpan) SetBaggage(key, value string) { + C.envoy_dynamic_module_callback_http_span_set_baggage( + s.spanPtr, + stringToModuleBuffer(key), + stringToModuleBuffer(value), + ) + runtime.KeepAlive(key) + runtime.KeepAlive(value) } -func (h *dymHttpFilterHandle) ClearDownstreamWatermarkCallbacks() { - h.downstreamWatermarkCallbacks = nil +func (s *dymSpan) GetTraceID() (shared.UnsafeEnvoyBuffer, bool) { + var valueView C.envoy_dynamic_module_type_envoy_buffer + ret := C.envoy_dynamic_module_callback_http_span_get_trace_id( + s.spanPtr, + &valueView, + ) + if !bool(ret) || valueView.ptr == nil || valueView.length == 0 { + return shared.UnsafeEnvoyBuffer{}, bool(ret) + } + return envoyBufferToUnsafeEnvoyBuffer(valueView), true } -func (h *dymHttpFilterHandle) RecordHistogramValue(id shared.MetricID, - value uint64, tagsValues ...string) shared.MetricsResult { - idUint64 := uint64(id) - // Prepare tag values. - tagValueViews := stringArrayToModuleBufferSlice(tagsValues) +func (s *dymSpan) GetSpanID() (shared.UnsafeEnvoyBuffer, bool) { + var valueView C.envoy_dynamic_module_type_envoy_buffer + ret := C.envoy_dynamic_module_callback_http_span_get_span_id( + s.spanPtr, + &valueView, + ) + if !bool(ret) || valueView.ptr == nil || valueView.length == 0 { + return shared.UnsafeEnvoyBuffer{}, bool(ret) + } + return envoyBufferToUnsafeEnvoyBuffer(valueView), true +} - ret := C.envoy_dynamic_module_callback_http_filter_record_histogram_value( - h.hostPluginPtr, - (C.size_t)(idUint64), - unsafe.SliceData(tagValueViews), - (C.size_t)(len(tagValueViews)), - (C.uint64_t)(value), +func (s *dymSpan) SpawnChild(operationName string) shared.ChildSpan { + childPtr := C.envoy_dynamic_module_callback_http_span_spawn_child( + s.hostPluginPtr, + s.spanPtr, + stringToModuleBuffer(operationName), ) + runtime.KeepAlive(operationName) + if childPtr == nil { + return nil + } + child := &dymChildSpan{ + childPtr: childPtr, + hostPluginPtr: s.hostPluginPtr, + filter: s.filter, + } + // trackChildSpan installs the GC finalizer (so a forgotten Finish is recovered) AND + // records the child on the filter so we can safely retire it if the stream is destroyed + // before the module finishes the span. + if s.filter != nil { + s.filter.trackChildSpan(child) + } else { + runtime.SetFinalizer(child, func(c *dymChildSpan) { c.Finish() }) + } + return child +} - runtime.KeepAlive(tagsValues) - runtime.KeepAlive(tagValueViews) - return shared.MetricsResult(ret) +// dymChildSpan implements shared.ChildSpan. The module owns the underlying span and must call +// Finish exactly once. Finish is also installed as a finalizer to avoid leaks if the module +// forgets. filter, when non-nil, is the owning filter handle: it tracks unfinished children +// so they can be marked finished (without invoking Envoy) when the stream is destroyed. +type dymChildSpan struct { + childPtr C.envoy_dynamic_module_type_child_span_module_ptr + hostPluginPtr C.envoy_dynamic_module_type_http_filter_envoy_ptr + filter *dymHttpFilterHandle + finishedMu sync.Mutex + finished bool } -func (h *dymHttpFilterHandle) SetGaugeValue(id shared.MetricID, - value uint64, tagsValues ...string) shared.MetricsResult { - idUint64 := uint64(id) - // Prepare tag values. - tagValueViews := stringArrayToModuleBufferSlice(tagsValues) +// asSpanPtr returns the child span as the generic span pointer accepted by the span_* callbacks. +// In the ABI both pointer types are void*, and Envoy resolves the right type via dynamic_cast. +func (c *dymChildSpan) asSpanPtr() C.envoy_dynamic_module_type_span_envoy_ptr { + return C.envoy_dynamic_module_type_span_envoy_ptr(c.childPtr) +} - ret := C.envoy_dynamic_module_callback_http_filter_set_gauge( - h.hostPluginPtr, - (C.size_t)(idUint64), - unsafe.SliceData(tagValueViews), - (C.size_t)(len(tagValueViews)), - (C.uint64_t)(value), +func (c *dymChildSpan) SetTag(key, value string) { + C.envoy_dynamic_module_callback_http_span_set_tag( + c.asSpanPtr(), + stringToModuleBuffer(key), + stringToModuleBuffer(value), ) + runtime.KeepAlive(key) + runtime.KeepAlive(value) +} - runtime.KeepAlive(tagsValues) - runtime.KeepAlive(tagValueViews) - return shared.MetricsResult(ret) +func (c *dymChildSpan) SetOperation(operation string) { + C.envoy_dynamic_module_callback_http_span_set_operation( + c.asSpanPtr(), + stringToModuleBuffer(operation), + ) + runtime.KeepAlive(operation) } -func (h *dymHttpFilterHandle) IncrementGaugeValue(id shared.MetricID, - value uint64, tagsValues ...string) shared.MetricsResult { - // Prepare tag values. - tagValueViews := stringArrayToModuleBufferSlice(tagsValues) - ret := C.envoy_dynamic_module_callback_http_filter_increment_gauge( - h.hostPluginPtr, - (C.size_t)(uint64(id)), - unsafe.SliceData(tagValueViews), - (C.size_t)(len(tagValueViews)), - (C.uint64_t)(value), +func (c *dymChildSpan) Log(event string) { + C.envoy_dynamic_module_callback_http_span_log( + c.hostPluginPtr, + c.asSpanPtr(), + stringToModuleBuffer(event), ) - runtime.KeepAlive(tagsValues) - runtime.KeepAlive(tagValueViews) - return shared.MetricsResult(ret) + runtime.KeepAlive(event) } -func (h *dymHttpFilterHandle) DecrementGaugeValue(id shared.MetricID, - value uint64, tagsValues ...string) shared.MetricsResult { - // Prepare tag values. - tagValueViews := stringArrayToModuleBufferSlice(tagsValues) - ret := C.envoy_dynamic_module_callback_http_filter_decrement_gauge( - h.hostPluginPtr, - (C.size_t)(uint64(id)), - unsafe.SliceData(tagValueViews), - (C.size_t)(len(tagValueViews)), - (C.uint64_t)(value), +func (c *dymChildSpan) SetSampled(sampled bool) { + C.envoy_dynamic_module_callback_http_span_set_sampled( + c.asSpanPtr(), + (C.bool)(sampled), ) - runtime.KeepAlive(tagsValues) - runtime.KeepAlive(tagValueViews) - return shared.MetricsResult(ret) } -func (h *dymHttpFilterHandle) IncrementCounterValue(id shared.MetricID, - value uint64, tagsValues ...string) shared.MetricsResult { - // Prepare tag values. - tagValueViews := stringArrayToModuleBufferSlice(tagsValues) - ret := C.envoy_dynamic_module_callback_http_filter_increment_counter( - h.hostPluginPtr, - (C.size_t)(uint64(id)), - unsafe.SliceData(tagValueViews), - (C.size_t)(len(tagValueViews)), - (C.uint64_t)(value), +func (c *dymChildSpan) SetBaggage(key, value string) { + C.envoy_dynamic_module_callback_http_span_set_baggage( + c.asSpanPtr(), + stringToModuleBuffer(key), + stringToModuleBuffer(value), ) - runtime.KeepAlive(tagsValues) - runtime.KeepAlive(tagValueViews) - return shared.MetricsResult(ret) + runtime.KeepAlive(key) + runtime.KeepAlive(value) +} + +func (c *dymChildSpan) SpawnChild(operationName string) shared.ChildSpan { + childPtr := C.envoy_dynamic_module_callback_http_span_spawn_child( + c.hostPluginPtr, + c.asSpanPtr(), + stringToModuleBuffer(operationName), + ) + runtime.KeepAlive(operationName) + if childPtr == nil { + return nil + } + child := &dymChildSpan{ + childPtr: childPtr, + hostPluginPtr: c.hostPluginPtr, + filter: c.filter, + } + if c.filter != nil { + c.filter.trackChildSpan(child) + } else { + runtime.SetFinalizer(child, func(c *dymChildSpan) { c.Finish() }) + } + return child +} + +func (c *dymChildSpan) Finish() { + c.finishedMu.Lock() + if c.finished { + c.finishedMu.Unlock() + return + } + c.finished = true + c.finishedMu.Unlock() + // Drop from the filter's tracking set BEFORE dispatching so a concurrent stream destroy + // won't double-process this span. + if c.filter != nil { + c.filter.untrackChildSpan(c) + } + C.envoy_dynamic_module_callback_http_child_span_finish(c.childPtr) + // Clear the finalizer so the GC anchor is released; harmless if no finalizer was set. + runtime.SetFinalizer(c, nil) } func newDymStreamPluginHandle( @@ -1597,7 +1701,10 @@ func newDymStreamPluginHandle( } type dymConfigHandle struct { - hostConfigPtr C.envoy_dynamic_module_type_http_filter_config_envoy_ptr + hostConfigPtr C.envoy_dynamic_module_type_http_filter_config_envoy_ptr + // Config-context callouts can complete on a different thread than the one that started + // them, so callout/stream maps need explicit synchronization. + calloutMu sync.Mutex calloutCallbacks map[uint64]shared.HttpCalloutCallback streamCallbacks map[uint64]shared.HttpStreamCallback scheduler *dymScheduler @@ -1709,10 +1816,12 @@ func (h *dymConfigHandle) HttpCallout( return goResult, 0 } + h.calloutMu.Lock() if h.calloutCallbacks == nil { h.calloutCallbacks = make(map[uint64]shared.HttpCalloutCallback) } h.calloutCallbacks[uint64(calloutID)] = cb + h.calloutMu.Unlock() return goResult, uint64(calloutID) } @@ -1744,10 +1853,12 @@ func (h *dymConfigHandle) StartHttpStream( return goResult, 0 } + h.calloutMu.Lock() if h.streamCallbacks == nil { h.streamCallbacks = make(map[uint64]shared.HttpStreamCallback) } h.streamCallbacks[uint64(streamID)] = cb + h.calloutMu.Unlock() return goResult, uint64(streamID) } @@ -1797,13 +1908,15 @@ func (h *dymConfigHandle) GetScheduler() shared.Scheduler { taskID, ) }, + func(p unsafe.Pointer) { + C.envoy_dynamic_module_callback_http_filter_config_scheduler_delete( + (C.envoy_dynamic_module_type_http_filter_config_scheduler_module_ptr)(p), + ) + }, ) - runtime.SetFinalizer(h.scheduler, func(s *dymScheduler) { - C.envoy_dynamic_module_callback_http_filter_config_scheduler_delete( - (C.envoy_dynamic_module_type_http_filter_config_scheduler_module_ptr)(s.schedulerPtr), - ) - }) + // See dymHttpFilterHandle.GetScheduler for why the finalizer is a fallback. + runtime.SetFinalizer(h.scheduler, func(s *dymScheduler) { s.close() }) } return h.scheduler } @@ -1841,12 +1954,16 @@ func envoy_dynamic_module_on_http_filter_config_new( config C.envoy_dynamic_module_type_envoy_buffer, ) C.envoy_dynamic_module_type_http_filter_config_module_ptr { nameString := envoyBufferToStringUnsafe(name) - configBytes := envoyBufferToBytesUnsafe(config) + configBytes := envoyBufferToBytesCopy(config) configHandle := &dymConfigHandle{hostConfigPtr: hostConfigPtr} factory, err := sdk.NewHttpFilterFactory(configHandle, nameString, configBytes) - if err != nil || factory == nil { - configHandle.Log(shared.LogLevelWarn, "Failed to load configuration: %v", err) + if err != nil { + configHandle.Log(shared.LogLevelWarn, "Failed to load HTTP filter configuration for %q: %v", nameString, err) + return nil + } + if factory == nil { + configHandle.Log(shared.LogLevelWarn, "Failed to load HTTP filter configuration for %q: factory returned nil", nameString) return nil } configPtr := configManager.record(&httpFilterConfigWrapper{pluginFactory: factory, configHandle: configHandle}) @@ -1861,7 +1978,12 @@ func envoy_dynamic_module_on_http_filter_config_destroy( if factoryWrapper == nil { return } - factoryWrapper.configHandle.scheduler = nil + if factoryWrapper.configHandle.scheduler != nil { + // See bootstrap config destroy for why we close synchronously instead of + // dropping the reference and waiting for the GC finalizer. + factoryWrapper.configHandle.scheduler.close() + factoryWrapper.configHandle.scheduler = nil + } factoryWrapper.pluginFactory.OnDestroy() configManager.remove(unsafe.Pointer(configPtr)) } @@ -1872,7 +1994,7 @@ func envoy_dynamic_module_on_http_filter_per_route_config_new( config C.envoy_dynamic_module_type_envoy_buffer, ) C.envoy_dynamic_module_type_http_filter_per_route_config_module_ptr { nameStr := envoyBufferToStringUnsafe(name) - configBytes := envoyBufferToBytesUnsafe(config) + configBytes := envoyBufferToBytesCopy(config) // The route config handle only make logging available. configHandle := &dymRouteConfigHandle{} @@ -1880,13 +2002,18 @@ func envoy_dynamic_module_on_http_filter_per_route_config_new( configFactory := sdk.GetHttpFilterConfigFactory(nameStr) if configFactory == nil { configHandle.Log(shared.LogLevelWarn, - "Failed to load configuration: no factory for %s", nameStr) + "Failed to load HTTP per-route configuration for %q: no factory registered", nameStr) return nil } parsedConfig, err := configFactory.CreatePerRoute(configBytes) - if err != nil || parsedConfig == nil { + if err != nil { + configHandle.Log(shared.LogLevelWarn, + "Failed to load HTTP per-route configuration for %q: %v", nameStr, err) + return nil + } + if parsedConfig == nil { configHandle.Log(shared.LogLevelWarn, - "Failed to load per-route configuration: %v", err) + "Failed to load HTTP per-route configuration for %q: factory returned nil", nameStr) return nil } @@ -1924,10 +2051,15 @@ func envoy_dynamic_module_on_http_filter_destroy( pluginPtr C.envoy_dynamic_module_type_http_filter_module_ptr, ) { pluginWrapper := pluginManager.unwrap(unsafe.Pointer(pluginPtr)) - if pluginWrapper == nil || pluginWrapper.streamDestoried { + if pluginWrapper == nil || pluginWrapper.streamDestroyed { return } - pluginWrapper.streamDestoried = true + // Mark destroyed FIRST so a concurrent SpawnChild seen via trackChildSpan won't register + // a new finalizer that would later fire against a freed span pointer. + pluginWrapper.childSpansMu.Lock() + pluginWrapper.streamDestroyed = true + pluginWrapper.childSpansMu.Unlock() + pluginWrapper.retireChildSpansOnDestroy() if pluginWrapper.plugin != nil { pluginWrapper.plugin.OnDestroy() } @@ -2028,9 +2160,14 @@ func envoy_dynamic_module_on_http_filter_stream_complete( return } pluginWrapper.streamCompleted = true - pluginWrapper.clearData() - pluginWrapper.scheduler = nil + if pluginWrapper.scheduler != nil { + // See bootstrap config destroy for why we close synchronously. + pluginWrapper.scheduler.close() + pluginWrapper.scheduler = nil + } pluginWrapper.plugin.OnStreamComplete() + // data is held in Go memory and is freed when the wrapper is GC'd after pluginManager + // removes it; no explicit teardown is needed. } //export envoy_dynamic_module_on_http_filter_scheduled @@ -2066,9 +2203,13 @@ func envoy_dynamic_module_on_http_filter_http_callout_done( resultHeaders := envoyHttpHeaderSliceToUnsafeHeaderSlice(unsafe.Slice(headers, int(headersSize))) resultChunks := envoyBufferSliceToUnsafeEnvoyBufferSlice(unsafe.Slice(chunks, int(chunksSize))) + pluginWrapper.calloutMu.Lock() cb := pluginWrapper.calloutCallbacks[uint64(calloutID)] if cb != nil { delete(pluginWrapper.calloutCallbacks, uint64(calloutID)) + } + pluginWrapper.calloutMu.Unlock() + if cb != nil { cb.OnHttpCalloutDone(uint64(calloutID), shared.HttpCalloutResult(result), resultHeaders, @@ -2094,7 +2235,9 @@ func envoy_dynamic_module_on_http_filter_http_stream_headers( // Prepare headers. resultHeaders := envoyHttpHeaderSliceToUnsafeHeaderSlice(unsafe.Slice(headers, int(headersSize))) + pluginWrapper.calloutMu.Lock() cb := pluginWrapper.streamCallbacks[uint64(streamID)] + pluginWrapper.calloutMu.Unlock() if cb != nil { cb.OnHttpStreamHeaders(uint64(streamID), resultHeaders, bool(endOfStream)) } @@ -2117,7 +2260,9 @@ func envoy_dynamic_module_on_http_filter_http_stream_data( // Prepare data. resultData := envoyBufferSliceToUnsafeEnvoyBufferSlice(unsafe.Slice(chunks, int(chunksSize))) + pluginWrapper.calloutMu.Lock() cb := pluginWrapper.streamCallbacks[uint64(streamID)] + pluginWrapper.calloutMu.Unlock() if cb != nil { cb.OnHttpStreamData(uint64(streamID), resultData, bool(endOfStream)) } @@ -2139,7 +2284,9 @@ func envoy_dynamic_module_on_http_filter_http_stream_trailers( // Prepare trailers. resultTrailers := envoyHttpHeaderSliceToUnsafeHeaderSlice(unsafe.Slice(trailers, int(trailersSize))) + pluginWrapper.calloutMu.Lock() cb := pluginWrapper.streamCallbacks[uint64(streamID)] + pluginWrapper.calloutMu.Unlock() if cb != nil { cb.OnHttpStreamTrailers(uint64(streamID), resultTrailers) } @@ -2156,9 +2303,13 @@ func envoy_dynamic_module_on_http_filter_http_stream_complete( return } + pluginWrapper.calloutMu.Lock() cb := pluginWrapper.streamCallbacks[uint64(streamID)] if cb != nil { delete(pluginWrapper.streamCallbacks, uint64(streamID)) + } + pluginWrapper.calloutMu.Unlock() + if cb != nil { cb.OnHttpStreamComplete(uint64(streamID)) } } @@ -2175,9 +2326,13 @@ func envoy_dynamic_module_on_http_filter_http_stream_reset( return } + pluginWrapper.calloutMu.Lock() cb := pluginWrapper.streamCallbacks[uint64(streamID)] if cb != nil { delete(pluginWrapper.streamCallbacks, uint64(streamID)) + } + pluginWrapper.calloutMu.Unlock() + if cb != nil { cb.OnHttpStreamReset(uint64(streamID), shared.HttpStreamResetReason(reason)) } } @@ -2214,20 +2369,18 @@ func envoy_dynamic_module_on_http_filter_downstream_below_write_buffer_low_water //export envoy_dynamic_module_on_http_filter_local_reply func envoy_dynamic_module_on_http_filter_local_reply( - filter_envoy_ptr C.envoy_dynamic_module_type_http_filter_envoy_ptr, + _ C.envoy_dynamic_module_type_http_filter_envoy_ptr, filter_module_ptr C.envoy_dynamic_module_type_http_filter_module_ptr, response_code C.uint32_t, details C.envoy_dynamic_module_type_envoy_buffer, reset_imminent C.bool, ) C.envoy_dynamic_module_type_on_http_filter_local_reply_status { - _ = filter_envoy_ptr pluginWrapper := pluginManager.unwrap(unsafe.Pointer(filter_module_ptr)) if pluginWrapper == nil || pluginWrapper.plugin == nil { return C.envoy_dynamic_module_type_on_http_filter_local_reply_status( shared.LocalReplyStatusContinue, ) } - return C.envoy_dynamic_module_type_on_http_filter_local_reply_status( pluginWrapper.plugin.OnLocalReply( uint32(response_code), @@ -2257,9 +2410,13 @@ func envoy_dynamic_module_on_http_filter_config_http_callout_done( resultHeaders := envoyHttpHeaderSliceToUnsafeHeaderSlice(unsafe.Slice(headers, int(headersSize))) resultChunks := envoyBufferSliceToUnsafeEnvoyBufferSlice(unsafe.Slice(chunks, int(chunksSize))) + ch.calloutMu.Lock() cb := ch.calloutCallbacks[uint64(calloutID)] if cb != nil { delete(ch.calloutCallbacks, uint64(calloutID)) + } + ch.calloutMu.Unlock() + if cb != nil { cb.OnHttpCalloutDone(uint64(calloutID), shared.HttpCalloutResult(result), resultHeaders, resultChunks) } } @@ -2281,7 +2438,9 @@ func envoy_dynamic_module_on_http_filter_config_http_stream_headers( resultHeaders := envoyHttpHeaderSliceToUnsafeHeaderSlice(unsafe.Slice(headers, int(headersSize))) + ch.calloutMu.Lock() cb := ch.streamCallbacks[uint64(streamID)] + ch.calloutMu.Unlock() if cb != nil { cb.OnHttpStreamHeaders(uint64(streamID), resultHeaders, bool(endOfStream)) } @@ -2304,7 +2463,9 @@ func envoy_dynamic_module_on_http_filter_config_http_stream_data( resultData := envoyBufferSliceToUnsafeEnvoyBufferSlice(unsafe.Slice(chunks, int(chunksSize))) + ch.calloutMu.Lock() cb := ch.streamCallbacks[uint64(streamID)] + ch.calloutMu.Unlock() if cb != nil { cb.OnHttpStreamData(uint64(streamID), resultData, bool(endOfStream)) } @@ -2326,7 +2487,9 @@ func envoy_dynamic_module_on_http_filter_config_http_stream_trailers( resultTrailers := envoyHttpHeaderSliceToUnsafeHeaderSlice(unsafe.Slice(trailers, int(trailersSize))) + ch.calloutMu.Lock() cb := ch.streamCallbacks[uint64(streamID)] + ch.calloutMu.Unlock() if cb != nil { cb.OnHttpStreamTrailers(uint64(streamID), resultTrailers) } @@ -2344,9 +2507,13 @@ func envoy_dynamic_module_on_http_filter_config_http_stream_complete( } ch := configWrapper.configHandle + ch.calloutMu.Lock() cb := ch.streamCallbacks[uint64(streamID)] if cb != nil { delete(ch.streamCallbacks, uint64(streamID)) + } + ch.calloutMu.Unlock() + if cb != nil { cb.OnHttpStreamComplete(uint64(streamID)) } } @@ -2364,9 +2531,13 @@ func envoy_dynamic_module_on_http_filter_config_http_stream_reset( } ch := configWrapper.configHandle + ch.calloutMu.Lock() cb := ch.streamCallbacks[uint64(streamID)] if cb != nil { delete(ch.streamCallbacks, uint64(streamID)) + } + ch.calloutMu.Unlock() + if cb != nil { cb.OnHttpStreamReset(uint64(streamID), shared.HttpStreamResetReason(reason)) } } diff --git a/source/extensions/dynamic_modules/sdk/go/abi/network.go b/source/extensions/dynamic_modules/sdk/go/abi/network.go index 7cc1e9e4cd35b..94b7e6826ea0f 100644 --- a/source/extensions/dynamic_modules/sdk/go/abi/network.go +++ b/source/extensions/dynamic_modules/sdk/go/abi/network.go @@ -9,6 +9,7 @@ import "C" import ( "runtime" + "sync" "unsafe" sdk "github.com/envoyproxy/envoy/source/extensions/dynamic_modules/sdk/go" @@ -20,10 +21,8 @@ type networkFilterConfigWrapper struct { configHandle *dymNetworkConfigHandle } -type networkFilterWrapper = dymNetworkFilterHandle - var networkConfigManager = newManager[networkFilterConfigWrapper]() -var networkPluginManager = newManager[networkFilterWrapper]() +var networkPluginManager = newManager[dymNetworkFilterHandle]() type dymNetworkBuffer struct { hostPluginPtr C.envoy_dynamic_module_type_network_filter_envoy_ptr @@ -130,10 +129,15 @@ func (b *dymNetworkBuffer) Append(data []byte) bool { } type dymNetworkFilterHandle struct { - hostPluginPtr C.envoy_dynamic_module_type_network_filter_envoy_ptr - plugin shared.NetworkFilter - readBuffer dymNetworkBuffer - writeBuffer dymNetworkBuffer + hostPluginPtr C.envoy_dynamic_module_type_network_filter_envoy_ptr + plugin shared.NetworkFilter + readBuffer dymNetworkBuffer + writeBuffer dymNetworkBuffer + // calloutMu guards calloutCallbacks. Per-connection network filter processing is + // single-threaded today, so this lock is uncontended in normal use; it's held for + // consistency with cluster/bootstrap callout maps and to keep the SDK safe if a future + // change introduces cross-thread callout dispatch. + calloutMu sync.Mutex calloutCallbacks map[uint64]shared.HttpCalloutCallback scheduler *dymScheduler filterDestroyed bool @@ -669,10 +673,12 @@ func (h *dymNetworkFilterHandle) HttpCallout( return goResult, 0 } + h.calloutMu.Lock() if h.calloutCallbacks == nil { h.calloutCallbacks = make(map[uint64]shared.HttpCalloutCallback) } h.calloutCallbacks[uint64(calloutID)] = cb + h.calloutMu.Unlock() return goResult, uint64(calloutID) } @@ -879,13 +885,15 @@ func (h *dymNetworkFilterHandle) GetScheduler() shared.Scheduler { taskID, ) }, + func(p unsafe.Pointer) { + C.envoy_dynamic_module_callback_network_filter_scheduler_delete( + C.envoy_dynamic_module_type_network_filter_scheduler_module_ptr(p), + ) + }, ) - runtime.SetFinalizer(h.scheduler, func(s *dymScheduler) { - C.envoy_dynamic_module_callback_network_filter_scheduler_delete( - C.envoy_dynamic_module_type_network_filter_scheduler_module_ptr(s.schedulerPtr), - ) - }) + // Finalizer is a fallback; the destroy hook should call close() synchronously. + runtime.SetFinalizer(h.scheduler, func(s *dymScheduler) { s.close() }) } return h.scheduler } @@ -951,15 +959,15 @@ func (h *dymNetworkConfigHandle) GetScheduler() shared.Scheduler { taskID, ) }, + func(p unsafe.Pointer) { + C.envoy_dynamic_module_callback_network_filter_config_scheduler_delete( + C.envoy_dynamic_module_type_network_filter_config_scheduler_module_ptr(p), + ) + }, ) - runtime.SetFinalizer(h.scheduler, func(s *dymScheduler) { - C.envoy_dynamic_module_callback_network_filter_config_scheduler_delete( - C.envoy_dynamic_module_type_network_filter_config_scheduler_module_ptr( - s.schedulerPtr, - ), - ) - }) + // Finalizer is a fallback; the destroy hook should call close() synchronously. + runtime.SetFinalizer(h.scheduler, func(s *dymScheduler) { s.close() }) } return h.scheduler } @@ -971,7 +979,7 @@ func envoy_dynamic_module_on_network_filter_config_new( config C.envoy_dynamic_module_type_envoy_buffer, ) C.envoy_dynamic_module_type_network_filter_config_module_ptr { nameString := envoyBufferToStringUnsafe(name) - configBytes := envoyBufferToBytesUnsafe(config) + configBytes := envoyBufferToBytesCopy(config) configHandle := &dymNetworkConfigHandle{hostConfigPtr: hostConfigPtr} factory, err := sdk.NewNetworkFilterFactory(configHandle, nameString, configBytes) @@ -1001,7 +1009,11 @@ func envoy_dynamic_module_on_network_filter_config_destroy( if configWrapper == nil { return } - configWrapper.configHandle.scheduler = nil + if configWrapper.configHandle.scheduler != nil { + // See bootstrap config destroy for why we close synchronously. + configWrapper.configHandle.scheduler.close() + configWrapper.configHandle.scheduler = nil + } configWrapper.pluginFactory.OnDestroy() networkConfigManager.remove(unsafe.Pointer(configPtr)) } @@ -1106,7 +1118,11 @@ func envoy_dynamic_module_on_network_filter_destroy( return } filterWrapper.filterDestroyed = true - filterWrapper.scheduler = nil + if filterWrapper.scheduler != nil { + // See bootstrap config destroy for why we close synchronously. + filterWrapper.scheduler.close() + filterWrapper.scheduler = nil + } if filterWrapper.plugin != nil { filterWrapper.plugin.OnDestroy() } @@ -1133,9 +1149,13 @@ func envoy_dynamic_module_on_network_filter_http_callout_done( resultHeaders := envoyHttpHeaderSliceToUnsafeHeaderSlice(unsafe.Slice(headers, int(headersSize))) resultChunks := envoyBufferSliceToUnsafeEnvoyBufferSlice(unsafe.Slice(chunks, int(chunksSize))) + filterWrapper.calloutMu.Lock() cb := filterWrapper.calloutCallbacks[uint64(calloutID)] if cb != nil { delete(filterWrapper.calloutCallbacks, uint64(calloutID)) + } + filterWrapper.calloutMu.Unlock() + if cb != nil { cb.OnHttpCalloutDone(uint64(calloutID), shared.HttpCalloutResult(result), resultHeaders, resultChunks) } } diff --git a/source/extensions/dynamic_modules/sdk/go/abi/scheduler.go b/source/extensions/dynamic_modules/sdk/go/abi/scheduler.go new file mode 100644 index 0000000000000..336f67a71bdc1 --- /dev/null +++ b/source/extensions/dynamic_modules/sdk/go/abi/scheduler.go @@ -0,0 +1,74 @@ +package abi + +/* +#cgo darwin LDFLAGS: -Wl,-undefined,dynamic_lookup +#cgo linux LDFLAGS: -Wl,--unresolved-symbols=ignore-all +#include +*/ +import "C" +import ( + "sync" + "unsafe" +) + +// dymScheduler is the SDK-side implementation of shared.Scheduler used by every extension +// surface that exposes a NewScheduler method (HTTP filter, network filter, cluster, bootstrap, +// etc.). It is defined here rather than in http.go so that the type's home file reflects its +// cross-surface role. +type dymScheduler struct { + schedulerPtr unsafe.Pointer + schedulerLock sync.Mutex + nextTaskID uint64 + tasks map[uint64]func() + commitFunc func(unsafe.Pointer, C.uint64_t) + // deleteFunc invokes the host's *_scheduler_delete callback for this scheduler. + // Stored here so close() can free the host-side allocation synchronously from the + // destroy hook (the finalizer-only path leaks under LeakSanitizer because Go GC + // finalizers don't run on process exit). + deleteFunc func(unsafe.Pointer) +} + +func newDymScheduler( + schedulerPtr unsafe.Pointer, + commitFunc func(unsafe.Pointer, C.uint64_t), + deleteFunc func(unsafe.Pointer), +) *dymScheduler { + return &dymScheduler{ + schedulerPtr: schedulerPtr, + tasks: make(map[uint64]func()), + commitFunc: commitFunc, + deleteFunc: deleteFunc, + } +} + +// close synchronously frees the host-side scheduler. Idempotent: subsequent calls and +// the runtime finalizer both no-op once schedulerPtr is nil. Must be called from the +// extension's destroy hook so the host allocation is reclaimed before the .so unloads. +func (s *dymScheduler) close() { + s.schedulerLock.Lock() + ptr := s.schedulerPtr + s.schedulerPtr = nil + s.schedulerLock.Unlock() + if ptr != nil && s.deleteFunc != nil { + s.deleteFunc(ptr) + } +} + +func (s *dymScheduler) Schedule(task func()) { + s.schedulerLock.Lock() + taskID := s.nextTaskID + s.nextTaskID++ + s.tasks[taskID] = task + s.schedulerLock.Unlock() + s.commitFunc(s.schedulerPtr, C.uint64_t(taskID)) +} + +func (s *dymScheduler) onScheduled(taskID uint64) { + s.schedulerLock.Lock() + task := s.tasks[taskID] + delete(s.tasks, taskID) + s.schedulerLock.Unlock() + if task != nil { + task() + } +} diff --git a/source/extensions/dynamic_modules/sdk/go/shared/api.go b/source/extensions/dynamic_modules/sdk/go/shared/api.go deleted file mode 100644 index 209d6ab702f16..0000000000000 --- a/source/extensions/dynamic_modules/sdk/go/shared/api.go +++ /dev/null @@ -1,225 +0,0 @@ -//go:generate mockgen -source=api.go -destination=mocks/mock_api.go -package=mocks -package shared - -type HeadersStatus int32 - -const ( - // '2' is preserved for ContinueAndDontEndStream and is not exposed here. - - // HeadersStatusContinue indicates that the headers can continue to be processed by - // next plugin in the chain and nothing will be stopped. - HeadersStatusContinue HeadersStatus = 0 - // HeadersStatusStop indicates that the headers processing should stop at this plugin. - // And when the body or trailers are received, the onRequestBody or onRequestTrailers - // of this plugin will be called. And the filter chain will continue or still hang - // based on the returned status of onRequestBody or onRequestTrailers. - // Of course the continueRequestStream or continueResponseStream can be called to continue - // the processing manually. - HeadersStatusStop HeadersStatus = 1 - // HeadersStatusStopAndBuffer indicates that the headers processing should stop at this plugin. - // And even if the body or trailers are received, the onRequestBody or onRequestTrailers - // of this plugin will NOT be called and the body will be buffered. The only way to continue - // the processing is to call continueRequestStream or continueResponseStream manually. - // This is useful when you want to wait a certain condition to be met before continuing - // the processing (For example, waiting for the result of an asynchronous operation). - HeadersStatusStopAllAndBuffer HeadersStatus = 3 - // Similar to HeadersStatusStopAllAndBuffer. But when there are too big body data buffered, - // the HeadersStatusStopAllAndBuffer will result in 413 (Payload Too Large) response to the - // client. But with this status, the watermarking will be used to disable reading from client - // or server. - HeadersStatusStopAllAndWatermark HeadersStatus = 4 - HeadersStatusDefault HeadersStatus = HeadersStatusContinue -) - -type BodyStatus int32 - -const ( - // BodyStatusContinue indicates that the body can continue to be processed by next plugin - // in the chain. And if the onRequestHeaders or onResponseHeaders of this plugin returned - // HeadersStatusStop before, the headers processing will continue. - BodyStatusContinue BodyStatus = 0 - // BodyStatusStopAndBuffer indicates that the body processing should stop at this plugin. - // And the body will be buffered. - BodyStatusStopAndBuffer BodyStatus = 1 - // BodyStatusStopAndWatermark indicates that the body processing should stop at this plugin. - // And watermarking will be used to disable reading from client or server if there are too - // big body data buffered. - BodyStatusStopAndWatermark BodyStatus = 2 - // BodyStatusStopNoBuffer indicates that the body processing should stop at this plugin. - // No body data will be buffered. - BodyStatusStopNoBuffer BodyStatus = 3 - BodyStatusDefault BodyStatus = BodyStatusContinue -) - -type TrailersStatus int32 - -const ( - // TrailersStatusContinue indicates that the trailers can continue to be processed by next plugin - // in the chain. And if the onRequestHeaders, onResponseHeaders, onRequestBody or onResponseBody - // of this plugin have returned stop status before, the processing will continue after this. - TrailersStatusContinue TrailersStatus = 0 - // TrailersStatusStop indicates that the trailers processing should stop at this plugin. The - // only way to continue the processing is to call continueRequestStream or continueResponseStream - // manually. - TrailersStatusStop TrailersStatus = 1 - TrailersStatusDefault TrailersStatus = TrailersStatusContinue -) - -type LocalReplyStatus int32 - -const ( - // LocalReplyStatusContinue indicates that the local reply should continue to be sent after all - // filters are informed. - LocalReplyStatusContinue LocalReplyStatus = 0 - // LocalReplyStatusContinueAndResetStream indicates that the local reply notification should - // continue to all filters, but the stream should be reset instead of sending the local reply. - LocalReplyStatusContinueAndResetStream LocalReplyStatus = 1 - LocalReplyStatusDefault LocalReplyStatus = LocalReplyStatusContinue -) - -// HttpFilter is the interface to implement your own plugin logic. This is a simplified version and could -// not implement flexible stream control. But it should be enough for most of the use cases. -type HttpFilter interface { - // OnRequestHeaders will be called when the request headers are received. - // @Param headers the request headers. - // @Param endOfStream whether this is the end of the stream. - // @Return HeadersStatus the status to control the plugin chain processing. - OnRequestHeaders(headers HeaderMap, endOfStream bool) HeadersStatus - - // OnRequestBody will be called when the request body are received. This may be called multiple times. - // @Param body the request body. - // @Param endOfStream whether this is the end of the stream. - // @Return BodyStatus the status to control the plugin chain processing. - OnRequestBody(body BodyBuffer, endOfStream bool) BodyStatus - - // OnRequestTrailers will be called when the request trailers are received. - // @Param trailers the request trailers. - // @Return TrailersStatus the status to control the plugin chain processing. - OnRequestTrailers(trailers HeaderMap) TrailersStatus - - // OnResponseHeaders will be called when the response headers are received. - // @Param headers the response headers. - // @Param endOfStream whether this is the end of the stream. - // @Return HeadersStatus the status to control the plugin chain processing. - OnResponseHeaders(headers HeaderMap, endOfStream bool) HeadersStatus - - // OnResponseBody will be called when the response body is received. This may be called multiple - // times. - // @Param body the response body. - // @Param endOfStream whether this is the end of the stream. - // @Return BodyStatus the status to control the plugin chain processing. - OnResponseBody(body BodyBuffer, endOfStream bool) BodyStatus - - // OnResponseTrailers will be called when the response trailers are received. - // @Param trailers the response trailers. - // @Return TrailersStatus the status to control the plugin chain processing. - OnResponseTrailers(trailers HeaderMap) TrailersStatus - - // OnStreamComplete is called when the stream processing is complete and before access logs - // are flushed. - // This is a good place to do any final processing or cleanup before the request is fully - // completed. - OnStreamComplete() - - // OnDestroy is called when the HTTP filter instance is being destroyed. This is called - // after OnStreamComplete and access logs are flushed. This is a good place to release - // any per-stream resources. - OnDestroy() - - // OnLocalReply is called when a local reply is being sent. This allows the filter to modify - // the local reply or decide to reset the stream instead. This is called before the local reply - // is sent to the client and before the stream is reset. - // @Param responseCode the response code of the local reply. - // @Param details the details of the local reply. This is usually used to indicate the reason - // for sending the local reply, for example, "buffer overflow" or "rate limit exceeded". - // @Param resetImminent whether the stream is going to be reset after this local reply. This allows - // the filter to decide whether to continue with sending the local reply or just reset the stream. - // @Return LocalReplyStatus the status to control whether to continue with sending the local reply - // or reset the stream. - OnLocalReply(responseCode uint32, details UnsafeEnvoyBuffer, resetImminent bool) LocalReplyStatus -} - -type EmptyHttpFilter struct { -} - -func (p *EmptyHttpFilter) OnRequestHeaders(headers HeaderMap, endOfStream bool) HeadersStatus { - return HeadersStatusDefault -} - -func (p *EmptyHttpFilter) OnRequestBody(body BodyBuffer, endOfStream bool) BodyStatus { - return BodyStatusDefault -} - -func (p *EmptyHttpFilter) OnRequestTrailers(trailers HeaderMap) TrailersStatus { - return TrailersStatusDefault -} - -func (p *EmptyHttpFilter) OnResponseHeaders(headers HeaderMap, endOfStream bool) HeadersStatus { - return HeadersStatusDefault -} - -func (p *EmptyHttpFilter) OnResponseBody(body BodyBuffer, endOfStream bool) BodyStatus { - return BodyStatusDefault -} - -func (p *EmptyHttpFilter) OnResponseTrailers(trailers HeaderMap) TrailersStatus { - return TrailersStatusDefault -} - -func (p *EmptyHttpFilter) OnStreamComplete() { -} - -func (p *EmptyHttpFilter) OnDestroy() { -} - -func (p *EmptyHttpFilter) OnLocalReply(responseCode uint32, details UnsafeEnvoyBuffer, resetImminent bool) LocalReplyStatus { - return LocalReplyStatusDefault -} - -// HttpFilterFactory is the factory interface for creating stream plugins. -// This is used to create instances of the stream plugin at runtime when a new request is received. -// The implementation of this interface should be thread-safe and hold the parsed configuration. -type HttpFilterFactory interface { - // Create creates a HttpFilter instance. - Create(handle HttpFilterHandle) HttpFilter - - // OnDestroy is called when the factory is being destroyed. This is a good place to clean up any - // resources. This usually happens when the configuration is updated and all existing streams - // using this factory are closed. - OnDestroy() -} - -type EmptyHttpFilterFactory struct { -} - -func (f *EmptyHttpFilterFactory) Create(handle HttpFilterHandle) HttpFilter { - return &EmptyHttpFilter{} -} - -func (f *EmptyHttpFilterFactory) OnDestroy() { -} - -// HttpFilterConfigFactory is the factory interface for creating stream plugin configurations. -// This is used to create -// PluginConfig based on the unparsed configuration. The HttpFilterConfigFactory should parse the unparsedConfig -// and create a PluginFactory instance. -// The implementation of this interface should be thread-safe and be stateless in most cases. -type HttpFilterConfigFactory interface { - // Create creates a HttpFilterFactory based on the unparsed configuration. - Create(handle HttpFilterConfigHandle, unparsedConfig []byte) (HttpFilterFactory, error) - - // CreatePerRoute creates a per-route configuration based on the unparsed configuration. - CreatePerRoute(unparsedConfig []byte) (any, error) -} - -type EmptyHttpFilterConfigFactory struct { -} - -func (f *EmptyHttpFilterConfigFactory) Create(handle HttpFilterConfigHandle, - unparsedConfig []byte) (HttpFilterFactory, error) { - return &EmptyHttpFilterFactory{}, nil -} - -func (f *EmptyHttpFilterConfigFactory) CreatePerRoute(unparsedConfig []byte) (any, error) { - return nil, nil -} diff --git a/source/extensions/dynamic_modules/sdk/go/shared/fake/fake_stream_base.go b/source/extensions/dynamic_modules/sdk/go/shared/fake/fake_http.go similarity index 95% rename from source/extensions/dynamic_modules/sdk/go/shared/fake/fake_stream_base.go rename to source/extensions/dynamic_modules/sdk/go/shared/fake/fake_http.go index a6fee1eacd60f..f642d361ee5ac 100644 --- a/source/extensions/dynamic_modules/sdk/go/shared/fake/fake_stream_base.go +++ b/source/extensions/dynamic_modules/sdk/go/shared/fake/fake_http.go @@ -7,6 +7,11 @@ import ( "github.com/envoyproxy/envoy/source/extensions/dynamic_modules/sdk/go/shared" ) +var ( + _ shared.HeaderMap = (*FakeHeaderMap)(nil) + _ shared.BodyBuffer = (*FakeBodyBuffer)(nil) +) + type FakeHeaderMap struct { Headers map[string][]string } diff --git a/source/extensions/dynamic_modules/sdk/go/shared/fake/fake_stream_base_test.go b/source/extensions/dynamic_modules/sdk/go/shared/fake/fake_http_test.go similarity index 100% rename from source/extensions/dynamic_modules/sdk/go/shared/fake/fake_stream_base_test.go rename to source/extensions/dynamic_modules/sdk/go/shared/fake/fake_http_test.go diff --git a/source/extensions/dynamic_modules/sdk/go/shared/base.go b/source/extensions/dynamic_modules/sdk/go/shared/http.go similarity index 51% rename from source/extensions/dynamic_modules/sdk/go/shared/base.go rename to source/extensions/dynamic_modules/sdk/go/shared/http.go index 807601c425433..c26ec22577b3f 100644 --- a/source/extensions/dynamic_modules/sdk/go/shared/base.go +++ b/source/extensions/dynamic_modules/sdk/go/shared/http.go @@ -1,54 +1,225 @@ -//go:generate mockgen -source=base.go -destination=mocks/mock_base.go -package=mocks +//go:generate mockgen -source=http.go -destination=mocks/mock_http.go -package=mocks package shared -import ( - "strings" - "unsafe" +// HTTP filter SDK surface for dynamic modules. +// +// Cross-surface primitives (UnsafeEnvoyBuffer, LogLevel, MetricID, AttributeID, Scheduler, +// HttpCalloutInitResult/Result/Callback, HttpStreamCallback/ResetReason, SocketOption*, +// ClusterHostCounts, HttpHeaderType) live in types.go. + +type HeadersStatus int32 + +const ( + // '2' is preserved for ContinueAndDontEndStream and is not exposed here. + + // HeadersStatusContinue indicates that the headers can continue to be processed by + // next plugin in the chain and nothing will be stopped. + HeadersStatusContinue HeadersStatus = 0 + // HeadersStatusStop indicates that the headers processing should stop at this plugin. + // And when the body or trailers are received, the onRequestBody or onRequestTrailers + // of this plugin will be called. And the filter chain will continue or still hang + // based on the returned status of onRequestBody or onRequestTrailers. + // Of course the continueRequestStream or continueResponseStream can be called to continue + // the processing manually. + HeadersStatusStop HeadersStatus = 1 + // HeadersStatusStopAndBuffer indicates that the headers processing should stop at this plugin. + // And even if the body or trailers are received, the onRequestBody or onRequestTrailers + // of this plugin will NOT be called and the body will be buffered. The only way to continue + // the processing is to call continueRequestStream or continueResponseStream manually. + // This is useful when you want to wait a certain condition to be met before continuing + // the processing (For example, waiting for the result of an asynchronous operation). + HeadersStatusStopAllAndBuffer HeadersStatus = 3 + // Similar to HeadersStatusStopAllAndBuffer. But when there are too big body data buffered, + // the HeadersStatusStopAllAndBuffer will result in 413 (Payload Too Large) response to the + // client. But with this status, the watermarking will be used to disable reading from client + // or server. + HeadersStatusStopAllAndWatermark HeadersStatus = 4 + HeadersStatusDefault HeadersStatus = HeadersStatusContinue +) + +type BodyStatus int32 + +const ( + // BodyStatusContinue indicates that the body can continue to be processed by next plugin + // in the chain. And if the onRequestHeaders or onResponseHeaders of this plugin returned + // HeadersStatusStop before, the headers processing will continue. + BodyStatusContinue BodyStatus = 0 + // BodyStatusStopAndBuffer indicates that the body processing should stop at this plugin. + // And the body will be buffered. + BodyStatusStopAndBuffer BodyStatus = 1 + // BodyStatusStopAndWatermark indicates that the body processing should stop at this plugin. + // And watermarking will be used to disable reading from client or server if there are too + // big body data buffered. + BodyStatusStopAndWatermark BodyStatus = 2 + // BodyStatusStopNoBuffer indicates that the body processing should stop at this plugin. + // No body data will be buffered. + BodyStatusStopNoBuffer BodyStatus = 3 + BodyStatusDefault BodyStatus = BodyStatusContinue +) + +type TrailersStatus int32 + +const ( + // TrailersStatusContinue indicates that the trailers can continue to be processed by next plugin + // in the chain. And if the onRequestHeaders, onResponseHeaders, onRequestBody or onResponseBody + // of this plugin have returned stop status before, the processing will continue after this. + TrailersStatusContinue TrailersStatus = 0 + // TrailersStatusStop indicates that the trailers processing should stop at this plugin. The + // only way to continue the processing is to call continueRequestStream or continueResponseStream + // manually. + TrailersStatusStop TrailersStatus = 1 + TrailersStatusDefault TrailersStatus = TrailersStatusContinue ) -// UnsafeEnvoyBuffer is a struct that represents a buffer of data from Envoy. -// It contains a pointer to the data and its length. The memory of the data is managed by Envoy. -type UnsafeEnvoyBuffer struct { - // Pointer to the start of the buffer data. - Ptr *byte - // Length of the buffer data in bytes. - Len uint64 +// LocalReplyStatus is returned from HttpFilter.OnLocalReply to control whether Envoy should +// send the local reply to the client or reset the stream instead. +type LocalReplyStatus int32 + +const ( + // LocalReplyStatusContinue indicates that the local reply should continue to be sent + // after all filters are informed. + LocalReplyStatusContinue LocalReplyStatus = 0 + // LocalReplyStatusContinueAndResetStream indicates that the local reply notification + // should continue to all filters, but the stream should be reset instead of sending + // the local reply. + LocalReplyStatusContinueAndResetStream LocalReplyStatus = 1 + LocalReplyStatusDefault LocalReplyStatus = LocalReplyStatusContinue +) + +// HttpFilter is the interface to implement your own plugin logic. This is a simplified version and could +// not implement flexible stream control. But it should be enough for most of the use cases. +type HttpFilter interface { + // OnRequestHeaders will be called when the request headers are received. + // Returns the status to control the plugin chain processing. + OnRequestHeaders(headers HeaderMap, endOfStream bool) HeadersStatus + + // OnRequestBody will be called when the request body are received. This may be called multiple times. + // Returns the status to control the plugin chain processing. + OnRequestBody(body BodyBuffer, endOfStream bool) BodyStatus + + // OnRequestTrailers will be called when the request trailers are received. + // Returns the status to control the plugin chain processing. + OnRequestTrailers(trailers HeaderMap) TrailersStatus + + // OnResponseHeaders will be called when the response headers are received. + // Returns the status to control the plugin chain processing. + OnResponseHeaders(headers HeaderMap, endOfStream bool) HeadersStatus + + // OnResponseBody will be called when the response body is received. This may be called multiple + // times. + // Returns the status to control the plugin chain processing. + OnResponseBody(body BodyBuffer, endOfStream bool) BodyStatus + + // OnResponseTrailers will be called when the response trailers are received. + // Returns the status to control the plugin chain processing. + OnResponseTrailers(trailers HeaderMap) TrailersStatus + + // OnStreamComplete is called when the stream processing is complete and before access logs + // are flushed. + // This is a good place to do any final processing or cleanup before the request is fully + // completed. + OnStreamComplete() + + // OnDestroy is called when the HTTP filter instance is being destroyed. This is called + // after OnStreamComplete and access logs are flushed. This is a good place to release + // any per-stream resources. + OnDestroy() + + // OnLocalReply is called when a local reply is being sent. The filter can either let the + // reply proceed (LocalReplyStatusContinue) or ask Envoy to reset the stream instead + // (LocalReplyStatusContinueAndResetStream). This is invoked before the reply leaves + // Envoy and before any stream reset. + // + // details is a short description of why the local reply is being sent (e.g. + // "buffer overflow", "rate limit exceeded"). The buffer aliases Envoy memory; copy + // before retaining past this call. resetImminent is true if Envoy is going to reset + // the stream after this call. + OnLocalReply(responseCode uint32, details UnsafeEnvoyBuffer, resetImminent bool) LocalReplyStatus +} + +type EmptyHttpFilter struct { +} + +func (p *EmptyHttpFilter) OnRequestHeaders(headers HeaderMap, endOfStream bool) HeadersStatus { + return HeadersStatusDefault +} + +func (p *EmptyHttpFilter) OnRequestBody(body BodyBuffer, endOfStream bool) BodyStatus { + return BodyStatusDefault +} + +func (p *EmptyHttpFilter) OnRequestTrailers(trailers HeaderMap) TrailersStatus { + return TrailersStatusDefault +} + +func (p *EmptyHttpFilter) OnResponseHeaders(headers HeaderMap, endOfStream bool) HeadersStatus { + return HeadersStatusDefault +} + +func (p *EmptyHttpFilter) OnResponseBody(body BodyBuffer, endOfStream bool) BodyStatus { + return BodyStatusDefault +} + +func (p *EmptyHttpFilter) OnResponseTrailers(trailers HeaderMap) TrailersStatus { + return TrailersStatusDefault +} + +func (p *EmptyHttpFilter) OnStreamComplete() { +} + +func (p *EmptyHttpFilter) OnLocalReply(_ uint32, _ UnsafeEnvoyBuffer, _ bool) LocalReplyStatus { + return LocalReplyStatusDefault +} + +func (p *EmptyHttpFilter) OnDestroy() { +} + +// HttpFilterFactory is the factory interface for creating stream plugins. +// This is used to create instances of the stream plugin at runtime when a new request is received. +// The implementation of this interface should be thread-safe and hold the parsed configuration. +type HttpFilterFactory interface { + // Create creates a HttpFilter instance. + Create(handle HttpFilterHandle) HttpFilter + + // OnDestroy is called when the factory is being destroyed. This is a good place to clean up any + // resources. This usually happens when the configuration is updated and all existing streams + // using this factory are closed. + OnDestroy() +} + +type EmptyHttpFilterFactory struct { +} + +func (f *EmptyHttpFilterFactory) Create(handle HttpFilterHandle) HttpFilter { + return &EmptyHttpFilter{} +} + +func (f *EmptyHttpFilterFactory) OnDestroy() { } -func (b UnsafeEnvoyBuffer) ToUnsafeBytes() []byte { - if b.Ptr == nil || b.Len == 0 { - return nil - } - // Use unsafe to create a byte slice that points to the buffer data without copying. - return unsafe.Slice(b.Ptr, b.Len) +// HttpFilterConfigFactory is the factory interface for creating stream plugin configurations. +// This is used to create +// PluginConfig based on the unparsed configuration. The HttpFilterConfigFactory should parse the unparsedConfig +// and create a PluginFactory instance. +// The implementation of this interface should be thread-safe and be stateless in most cases. +type HttpFilterConfigFactory interface { + // Create creates a HttpFilterFactory based on the unparsed configuration. + Create(handle HttpFilterConfigHandle, unparsedConfig []byte) (HttpFilterFactory, error) + + // CreatePerRoute creates a per-route configuration based on the unparsed configuration. + CreatePerRoute(unparsedConfig []byte) (any, error) } -// ToBytes converts the UnsafeEnvoyBuffer to a byte slice. It creates a copy of the data in Go memory. -func (b UnsafeEnvoyBuffer) ToBytes() []byte { - if b.Ptr == nil || b.Len == 0 { - return nil - } - // Create a byte slice that copys the data from the buffer. - owned := make([]byte, b.Len) - // Use unsafe to copy the data from the buffer to the byte slice. - src := unsafe.Slice(b.Ptr, b.Len) - copy(owned, src) - return owned +type EmptyHttpFilterConfigFactory struct { } -func (b UnsafeEnvoyBuffer) ToUnsafeString() string { - if b.Ptr == nil || b.Len == 0 { - return "" - } - // Use unsafe to create a string that points to the buffer data without copying. - return unsafe.String(b.Ptr, b.Len) +func (f *EmptyHttpFilterConfigFactory) Create(handle HttpFilterConfigHandle, + unparsedConfig []byte) (HttpFilterFactory, error) { + return &EmptyHttpFilterFactory{}, nil } -func (b UnsafeEnvoyBuffer) ToString() string { - if b.Ptr == nil || b.Len == 0 { - return "" - } - return strings.Clone(b.ToUnsafeString()) +func (f *EmptyHttpFilterConfigFactory) CreatePerRoute(unparsedConfig []byte) (any, error) { + return nil, nil } // BodyBuffer is an interface that provides access to the request and response body. @@ -63,11 +234,9 @@ type BodyBuffer interface { GetSize() uint64 // Drain removes the specified number of bytes from the beginning of the body buffer. - // @Param numBytes the number of bytes to drain. Drain(numBytes uint64) // Append adds the specified bytes to the end of the body buffer. - // @Param data the bytes to append. Append(data []byte) } @@ -103,177 +272,8 @@ type HeaderMap interface { Remove(key string) } -type AttributeID uint32 - -const ( - // request.path - AttributeIDRequestPath AttributeID = iota - // request.url_path - AttributeIDRequestUrlPath - // request.host - AttributeIDRequestHost - // request.scheme - AttributeIDRequestScheme - // request.method - AttributeIDRequestMethod - // request.headers - AttributeIDRequestHeaders - // request.referer - AttributeIDRequestReferer - // request.useragent - AttributeIDRequestUserAgent - // request.time - AttributeIDRequestTime - // request.id - AttributeIDRequestId - // request.protocol - AttributeIDRequestProtocol - // request.query - AttributeIDRequestQuery - // request.duration - AttributeIDRequestDuration - // request.size - AttributeIDRequestSize - // request.total_size - AttributeIDRequestTotalSize - // response.code - AttributeIDResponseCode - // response.code_details - AttributeIDResponseCodeDetails - // response.flags - AttributeIDResponseFlags - // response.grpc_status - AttributeIDResponseGrpcStatus - // response.headers - AttributeIDResponseHeaders - // response.trailers - AttributeIDResponseTrailers - // response.size - AttributeIDResponseSize - // response.total_size - AttributeIDResponseTotalSize - // response.backend_latency - AttributeIDResponseBackendLatency - // source.address - AttributeIDSourceAddress - // source.port - AttributeIDSourcePort - // destination.address - AttributeIDDestinationAddress - // destination.port - AttributeIDDestinationPort - // connection.id - AttributeIDConnectionId - // connection.mtls - AttributeIDConnectionMtls - // connection.requested_server_name - AttributeIDConnectionRequestedServerName - // connection.tls_version - AttributeIDConnectionTlsVersion - // connection.subject_local_certificate - AttributeIDConnectionSubjectLocalCertificate - // connection.subject_peer_certificate - AttributeIDConnectionSubjectPeerCertificate - // connection.dns_san_local_certificate - AttributeIDConnectionDnsSanLocalCertificate - // connection.dns_san_peer_certificate - AttributeIDConnectionDnsSanPeerCertificate - // connection.uri_san_local_certificate - AttributeIDConnectionUriSanLocalCertificate - // connection.uri_san_peer_certificate - AttributeIDConnectionUriSanPeerCertificate - // connection.sha256_peer_certificate_digest - AttributeIDConnectionSha256PeerCertificateDigest - // connection.transport_failure_reason - AttributeIDConnectionTransportFailureReason - // connection.termination_details - AttributeIDConnectionTerminationDetails - // upstream.address - AttributeIDUpstreamAddress - // upstream.port - AttributeIDUpstreamPort - // upstream.tls_version - AttributeIDUpstreamTlsVersion - // upstream.subject_local_certificate - AttributeIDUpstreamSubjectLocalCertificate - // upstream.subject_peer_certificate - AttributeIDUpstreamSubjectPeerCertificate - // upstream.dns_san_local_certificate - AttributeIDUpstreamDnsSanLocalCertificate - // upstream.dns_san_peer_certificate - AttributeIDUpstreamDnsSanPeerCertificate - // upstream.uri_san_local_certificate - AttributeIDUpstreamUriSanLocalCertificate - // upstream.uri_san_peer_certificate - AttributeIDUpstreamUriSanPeerCertificate - // upstream.sha256_peer_certificate_digest - AttributeIDUpstreamSha256PeerCertificateDigest - // upstream.local_address - AttributeIDUpstreamLocalAddress - // upstream.transport_failure_reason - AttributeIDUpstreamTransportFailureReason - // upstream.request_attempt_count - AttributeIDUpstreamRequestAttemptCount - // upstream.cx_pool_ready_duration - AttributeIDUpstreamCxPoolReadyDuration - // upstream.locality - AttributeIDUpstreamLocality - // xds.node - AttributeIDXdsNode - // xds.cluster_name - AttributeIDXdsClusterName - // xds.cluster_metadata - AttributeIDXdsClusterMetadata - // xds.listener_direction - AttributeIDXdsListenerDirection - // xds.listener_metadata - AttributeIDXdsListenerMetadata - // xds.route_name - AttributeIDXdsRouteName - // xds.route_metadata - AttributeIDXdsRouteMetadata - // xds.virtual_host_name - AttributeIDXdsVirtualHostName - // xds.virtual_host_metadata - AttributeIDXdsVirtualHostMetadata - // xds.upstream_host_metadata - AttributeIDXdsUpstreamHostMetadata - // xds.filter_chain_name - AttributeIDXdsFilterChainName - // health_check - AttributeIDHealthCheck -) - -type LogLevel uint32 - -const ( - LogLevelTrace LogLevel = iota - LogLevelDebug - LogLevelInfo - LogLevelWarn - LogLevelError - LogLevelCritical - LogLevelOff -) - -type HttpCalloutInitResult uint32 - -const ( - HttpCalloutInitSuccess HttpCalloutInitResult = iota - HttpCalloutInitMissingRequiredHeaders - HttpCalloutInitClusterNotFound - HttpCalloutInitDuplicateCalloutId - HttpCalloutInitCannotCreateRequest -) - -type HttpCalloutResult uint32 - -const ( - HttpCalloutSuccess HttpCalloutResult = iota - HttpCalloutReset - HttpCalloutExceedResponseBufferLimit -) - +// MetadataSourceType identifies which metadata source to read from. Corresponds to +// envoy_dynamic_module_type_metadata_source. type MetadataSourceType uint32 const ( @@ -284,134 +284,125 @@ const ( MetadataSourceTypeHostLocality ) -type HttpCalloutCallback interface { - OnHttpCalloutDone(calloutID uint64, result HttpCalloutResult, - headers [][2]UnsafeEnvoyBuffer, body []UnsafeEnvoyBuffer) -} - -type HttpStreamResetReason uint32 +// HttpFilterStreamResetReason is the reason for resetting the main HTTP stream via +// HttpFilterHandle.ResetStream. This corresponds to envoy_dynamic_module_type_http_filter_stream_reset_reason +// in the dynamic module ABI. +type HttpFilterStreamResetReason uint32 const ( - HttpStreamResetReasonConnectionFailure = iota - HttpStreamResetReasonConnectionTermination - HttpStreamResetReasonLocalReset - HttpStreamResetReasonLocalRefusedStreamReset - HttpStreamResetReasonOverflow - HttpStreamResetReasonRemoteReset - HttpStreamResetReasonRemoteRefusedStreamReset - HttpStreamResetReasonProtocolError + // HttpFilterStreamResetReasonLocalReset indicates a local codec level reset was sent on the stream. + HttpFilterStreamResetReasonLocalReset HttpFilterStreamResetReason = iota + // HttpFilterStreamResetReasonLocalRefusedStreamReset indicates a local codec level refused stream + // reset was sent on the stream (allowing for retry). + HttpFilterStreamResetReasonLocalRefusedStreamReset ) -type HttpStreamCallback interface { - OnHttpStreamHeaders(streamID uint64, headers [][2]UnsafeEnvoyBuffer, endStream bool) - OnHttpStreamData(streamID uint64, body []UnsafeEnvoyBuffer, endStream bool) - OnHttpStreamTrailers(streamID uint64, trailers [][2]UnsafeEnvoyBuffer) - OnHttpStreamComplete(streamID uint64) - OnHttpStreamReset(streamID uint64, reason HttpStreamResetReason) -} - -// Scheduler is the interface that provides scheduling capabilities for asynchronous operations. -// This allow the plugins run tasks in another thread and continue the processing later at the -// thread where the stream plugin is being processed. -type Scheduler interface { - // Schedule schedules a function to be executed asynchronously in the thread where the stream - // plugin is being processed. - // @Param func the function to be executed. - // NOTE: This function may be ignored if the related plugin processing is completed. - Schedule(func()) -} +// Span is a tracing span associated with the current HTTP stream. It is owned by Envoy and is +// valid for the lifetime of the HTTP stream. Modules MUST NOT call Finish on the active span - +// it is managed by Envoy. Use SpawnChild to create child spans whose lifetime the module owns. +type Span interface { + // SetTag sets a key/value tag on the span. + SetTag(key, value string) -type DownstreamWatermarkCallbacks interface { - OnAboveWriteBufferHighWatermark() - OnBelowWriteBufferLowWatermark() -} + // SetOperation sets the operation name on the span. + SetOperation(operation string) -type HttpFilterStreamResetReason uint32 + // Log records an event on the span with the current timestamp. + Log(event string) -const ( - HttpFilterStreamResetReasonLocalReset HttpFilterStreamResetReason = iota - HttpFilterStreamResetReasonLocalRefusedStreamReset -) + // SetSampled overrides the sampling decision for the span. If sampled is false, this span and + // any subsequent child spans will not be reported to the tracing system. + SetSampled(sampled bool) -type SocketOptionState uint32 + // GetBaggage retrieves a baggage value from the span. Returns the value and true if the key + // was found, otherwise an empty buffer and false. + // NOTE: The memory of the underlying data may not be managed by Go GC. Copy the data if you + // need to keep it past the current callback. + GetBaggage(key string) (UnsafeEnvoyBuffer, bool) -const ( - SocketOptionStatePrebind SocketOptionState = iota - SocketOptionStateBound - SocketOptionStateListening -) + // SetBaggage sets a baggage value on the span. All subsequent child spans will have access to + // this baggage. + SetBaggage(key, value string) -type SocketDirection uint32 + // GetTraceID retrieves the trace ID from the span. Returns the value and true if available, + // otherwise an empty buffer and false. + // NOTE: The memory of the underlying data may not be managed by Go GC. Copy the data if you + // need to keep it past the current callback. + GetTraceID() (UnsafeEnvoyBuffer, bool) -const ( - SocketDirectionUpstream SocketDirection = iota - SocketDirectionDownstream -) + // GetSpanID retrieves the span ID from the span. Returns the value and true if available, + // otherwise an empty buffer and false. + // NOTE: The memory of the underlying data may not be managed by Go GC. Copy the data if you + // need to keep it past the current callback. + GetSpanID() (UnsafeEnvoyBuffer, bool) -type ClusterHostCounts struct { - Total uint64 - Healthy uint64 - Degraded uint64 + // SpawnChild creates a child span with the given operation name. The returned ChildSpan must + // be finished by calling its Finish method when the module is done with it. Returns nil if + // the child span could not be created. + SpawnChild(operationName string) ChildSpan } -type Span interface { +// ChildSpan is a tracing span owned by the module. It must be finished by calling Finish when +// the module is done with it. +type ChildSpan interface { + // SetTag sets a key/value tag on the span. SetTag(key, value string) + + // SetOperation sets the operation name on the span. SetOperation(operation string) + + // Log records an event on the span with the current timestamp. Log(event string) + + // SetSampled overrides the sampling decision for the span. SetSampled(sampled bool) - GetBaggage(key string) (UnsafeEnvoyBuffer, bool) + + // SetBaggage sets a baggage value on the span. All subsequent child spans will have access to + // this baggage. SetBaggage(key, value string) - GetTraceID() (UnsafeEnvoyBuffer, bool) - GetSpanID() (UnsafeEnvoyBuffer, bool) - SpawnChild(operation string) ChildSpan -} -type ChildSpan interface { - Span + // SpawnChild creates a child span from this span with the given operation name. Returns nil + // if the child span could not be created. + SpawnChild(operationName string) ChildSpan + + // Finish finishes and releases this span. After calling this method, the span is no longer + // valid and must not be used. Calling Finish more than once is a no-op. Finish() } +// DownstreamWatermarkCallbacks is the callback interface invoked when the downstream connection +// crosses the configured write-buffer high/low watermark. +type DownstreamWatermarkCallbacks interface { + OnAboveWriteBufferHighWatermark() + OnBelowWriteBufferLowWatermark() +} + // HttpFilterHandle is the interface that provides access to the plugin's context and configuration. // This should be implemented by the SDK or runtime. type HttpFilterHandle interface { // GetMetadataString retrieves the dynamic metadata string value of the stream. - // @Param source the metadata source type. - // @Param metadataNamespace the metadata namespace. - // @Param key the metadata key. - // @Return the metadata value if found, otherwise an empty UnsafeEnvoyBuffer. + // Returns metadata value if found, otherwise an empty UnsafeEnvoyBuffer. GetMetadataString(source MetadataSourceType, metadataNamespace, key string) (UnsafeEnvoyBuffer, bool) // GetMetadataNumber retrieves the dynamic metadata number value of the stream. - // @Param source the metadata source type. - // @Param metadataNamespace the metadata namespace. - // @Param key the metadata key. - // @Return the metadata value if found, otherwise nil. + // Returns metadata value if found, otherwise nil. GetMetadataNumber(source MetadataSourceType, metadataNamespace, key string) (float64, bool) // GetMetadataBool retrieves the dynamic metadata bool value of the stream. - // @Param source the metadata source type. - // @Param metadataNamespace the metadata namespace. - // @Param key the metadata key. - // @Return the metadata value and true if found, otherwise false. + // Returns metadata value and true if found, otherwise false. GetMetadataBool(source MetadataSourceType, metadataNamespace, key string) (bool, bool) // SetMetadata sets the dynamic metadata value of the stream. - // @Param metadataNamespace the metadata namespace. - // @Param key the metadata key. - // @Param value the metadata value. Only string/int/float/bool are supported. SetMetadata(metadataNamespace, key string, value any) // GetMetadataKeys retrieves all keys in the given metadata namespace. - // @Param source the metadata source type. - // @Param metadataNamespace the metadata namespace. - // @Return the list of keys in the namespace, or nil if the namespace does not exist. + // Returns list of keys in the namespace, or nil if the namespace does not exist. // NOTE: The memory of underlying data may not be managed by Go GC. So you should // copy the data if you need to keep it and use it later. GetMetadataKeys(source MetadataSourceType, metadataNamespace string) []UnsafeEnvoyBuffer // GetMetadataNamespaces retrieves all namespace names in the metadata. - // @Param source the metadata source type. - // @Return the list of namespace names, or nil if no namespaces exist. + // Returns list of namespace names, or nil if no namespaces exist. // NOTE: The memory of underlying data may not be managed by Go GC. So you should // copy the data if you need to keep it and use it later. GetMetadataNamespaces(source MetadataSourceType) []UnsafeEnvoyBuffer @@ -457,88 +448,57 @@ type HttpFilterHandle interface { GetMetadataListBool(source MetadataSourceType, metadataNamespace, key string, index int) (bool, bool) // GetFilterState retrieves the serialized filter state value of the stream. - // @Param key the filter state key. - // @Return the filter state value if found, otherwise an empty UnsafeEnvoyBuffer. + // Returns filter state value if found, otherwise an empty UnsafeEnvoyBuffer. // NOTE: The memory of underlying data may not be managed by Go GC. So you should // copy the data if you need to keep it and use it later. GetFilterState(key string) (UnsafeEnvoyBuffer, bool) // SetFilterState sets the serialized filter state value of the stream. - // @Param key the filter state key. - // @Param value the filter state value. SetFilterState(key string, value []byte) - // SetFilterStateTyped sets a typed filter state object from serialized bytes using the registered - // Envoy ObjectFactory for the given key. - // @Param key the filter state key. - // @Param value the serialized bytes used to construct the typed object. - // @Return true if the value was stored successfully, otherwise false. - SetFilterStateTyped(key string, value []byte) bool - // GetAttributeString retrieves the string attribute value of the stream. - // @Param attributeID the attribute ID. - // @Return the attribute value if found, otherwise an empty UnsafeEnvoyBuffer. + // Returns attribute value if found, otherwise an empty UnsafeEnvoyBuffer. // NOTE: The memory of underlying data may not be managed by Go GC. So you should // copy the data if you need to keep it and use it later. GetAttributeString(attributeID AttributeID) (UnsafeEnvoyBuffer, bool) - // GetAttributeNumber retrieves the float attribute value of the stream. - // @Param key the attribute key. - // @Return the attribute value if found, otherwise nil. - GetAttributeNumber(attributeID AttributeID) (float64, bool) + // GetAttributeNumber retrieves the integer attribute value of the stream. + // Returns attribute value if found, otherwise (0, false). + GetAttributeNumber(attributeID AttributeID) (uint64, bool) // GetAttributeBool retrieves the bool attribute value of the stream. - // @Param attributeID the attribute ID. - // @Return the attribute value and true if found, otherwise false. + // Returns attribute value and true if found, otherwise false. GetAttributeBool(attributeID AttributeID) (bool, bool) - // GetFilterStateTyped retrieves the serialized value of a typed filter state object. - // @Param key the filter state key. - // @Return the serialized value if found, otherwise an empty UnsafeEnvoyBuffer. - GetFilterStateTyped(key string) (UnsafeEnvoyBuffer, bool) - // GetData retrieves internal data stored for cross-phase communication. // This data is not included in DynamicMetadata responses. - // @Param key the data key. - // @Return the data value if found, otherwise nil. + // Returns data value if found, otherwise nil. GetData(key string) any // SetData sets internal data for cross-phase communication. // This data is not included in DynamicMetadata responses. - // @Param key the data key. - // @Param value the data value. SetData(key string, value any) // SendLocalResponse sends a local reply to the client and terminates the stream. - // @Param status the HTTP status code. - // @Param headers the response headers. - // @Param body the response body. - // @Param detail a short description to the response for debugging purposes. SendLocalResponse(status uint32, headers [][2]string, body []byte, detail string) // SendResponseHeaders sends response headers to the client. This is used for // streaming local replies. // - // @Param headers the response headers. - // @Param endOfStream whether this is the end of the stream. SendResponseHeaders(headers [][2]string, endOfStream bool) // SendResponseData sends response body data to the client. This is used for // streaming local replies. // - // @Param body the response body data. - // @Param endOfStream whether this is the end of the stream. SendResponseData(body []byte, endOfStream bool) // SendResponseTrailers sends response trailers to the client. This is used for // streaming local replies. // - // @Param trailers the response trailers. SendResponseTrailers(trailers [][2]string) // AddCustomFlag adds a custom flag to the stream. This flag should be very short // string to indicate some custom state or information of the stream. - // @Param flag the custom flag to add. AddCustomFlag(flag string) // ContinueRequest continues the request stream processing. @@ -560,51 +520,8 @@ type HttpFilterHandle interface { // cluster selection but not the route itself. RefreshRouteCluster() - // GetWorkerIndex returns the worker index assigned to the current filter instance. - GetWorkerIndex() uint32 - - // SetSocketOptionInt sets an integer socket option on the upstream or downstream connection. - SetSocketOptionInt(level, name int64, state SocketOptionState, direction SocketDirection, value int64) bool - - // SetSocketOptionBytes sets a bytes socket option on the upstream or downstream connection. - SetSocketOptionBytes(level, name int64, state SocketOptionState, direction SocketDirection, value []byte) bool - - // GetSocketOptionInt retrieves an integer socket option from the upstream or downstream connection. - GetSocketOptionInt(level, name int64, state SocketOptionState, direction SocketDirection) (int64, bool) - - // GetSocketOptionBytes retrieves a bytes socket option from the upstream or downstream connection. - GetSocketOptionBytes(level, name int64, state SocketOptionState, direction SocketDirection) (UnsafeEnvoyBuffer, bool) - - // GetBufferLimit returns the current body buffering limit in bytes. - GetBufferLimit() uint64 - - // SetBufferLimit sets the current body buffering limit in bytes. - SetBufferLimit(limit uint64) - - // GetActiveSpan retrieves the active tracing span for the stream. - GetActiveSpan() Span - - // GetClusterName retrieves the selected upstream cluster name for the stream. - GetClusterName() (UnsafeEnvoyBuffer, bool) - - // GetClusterHostCounts retrieves the total, healthy, and degraded host counts for the selected - // cluster at the given priority. - GetClusterHostCounts(priority uint32) (ClusterHostCounts, bool) - - // SetUpstreamOverrideHost sets an override host for the selected upstream cluster. - SetUpstreamOverrideHost(host string, strict bool) bool - - // ResetStream resets the downstream HTTP stream with the given reason and details string. - ResetStream(reason HttpFilterStreamResetReason, details string) - - // SendGoAwayAndClose sends a GOAWAY frame to the downstream and closes the connection. - SendGoAwayAndClose(graceful bool) - - // RecreateStream recreates the HTTP stream, optionally with replacement headers. - RecreateStream(headers [][2]string) bool - // RequestHeaders retrieves the request headers. - // @Return the request headers. + // Returns request headers. RequestHeaders() HeaderMap // BufferedRequestBody retrieves the buffered request body in the chain. @@ -613,7 +530,7 @@ type HttpFilterHandle interface { // currently buffered body in the chain. And the latest newly received body chunk is passed // as the parameter to OnRequestBody. Only when endOfStream is true or OnRequestTrailers is // called, the full request body is received. - // @Return the buffered request body. + // Returns buffered request body. BufferedRequestBody() BodyBuffer // ReceivedRequestBody retrieves the latest received request body chunk in the OnRequestBody callback. @@ -623,11 +540,11 @@ type HttpFilterHandle interface { ReceivedRequestBody() BodyBuffer // RequestTrailers retrieves the request trailers. - // @Return the request trailers. + // Returns request trailers. RequestTrailers() HeaderMap // ResponseHeaders retrieves the response headers. - // @Return the response headers. + // Returns response headers. ResponseHeaders() HeaderMap // BufferedResponseBody retrieves the buffered response body in the chain. @@ -636,7 +553,7 @@ type HttpFilterHandle interface { // currently buffered body in the chain. And the latest newly received body chunk is passed // as the parameter to OnResponseBody. Only when endOfStream is true or OnResponseTrailers is // called, the full request body is received. - // @Return the buffered response body. + // Returns buffered response body. BufferedResponseBody() BodyBuffer // ReceivedResponseBody retrieves the latest received response body chunk in the OnResponseBody callback. @@ -660,7 +577,7 @@ type HttpFilterHandle interface { ReceivedBufferedResponseBody() bool // ResponseTrailers retrieves the response trailers. - // @Return the response trailers. + // Returns response trailers. ResponseTrailers() HeaderMap // GetMostSpecificConfig retrieves the most specific route configuration for the stream. @@ -679,15 +596,10 @@ type HttpFilterHandle interface { // HttpCallout performs an HTTP call to an external service. The call is asynchronous, and the // response will be delivered via the provided callback. - // @Param cluster the cluster (target) name to which the HTTP call will be made. - // @Param headers the HTTP headers to be sent with the request. - // @Param body the HTTP body to be sent with the request. - // @Param timeoutMs the timeout in milliseconds for the HTTP call. - // @Param callback the callback function to be invoked when the response is received or an // error occurs. // The callback function receives the response headers, body, and an error if any occurred. // - // @Return the result of the HTTP callout initialization and the callout ID. Non-success results + // Returns result of the HTTP callout initialization and the callout ID. Non-success results // indicate that the callout failed to start. // // NOTE: This method should only be called during OnRequest* or OnResponse* callbacks or @@ -698,14 +610,8 @@ type HttpFilterHandle interface { // StartHttpStream starts a new HTTP stream to an external service. The stream is asynchronous, // and the response will be delivered via the provided callback. - // @Param cluster the cluster (target) name to which the HTTP stream will be made. - // @Param headers the initial HTTP headers to be sent with the request. - // @Param body the initial HTTP body to be sent with the request. - // @Param endOfStream whether this is the end of the stream. - // @Param timeoutMs the timeout in milliseconds for the HTTP stream. - // @Param callback the callback interface to handle the stream events. // - // @Return the result of the HTTP stream initialization and the stream ID. Non-success results + // Returns result of the HTTP stream initialization and the stream ID. Non-success results // indicate that the stream failed to start. // // NOTE: This method should only be called during OnRequest* or OnResponse* callbacks or @@ -715,11 +621,8 @@ type HttpFilterHandle interface { cb HttpStreamCallback) (HttpCalloutInitResult, uint64) // SendHttpStreamData sends data on an existing HTTP stream. - // @Param streamID the ID of the HTTP stream. - // @Param body the HTTP body to be sent with the request. - // @Param endOfStream whether this is the end of the stream. // - // @Return whether the data was successfully sent. + // Returns the data was successfully sent. // // NOTE: This method should only be called during OnRequest* or OnResponse* callbacks or // scheduled functions via the Scheduler. By this way we can ensure this is only be called @@ -727,10 +630,8 @@ type HttpFilterHandle interface { SendHttpStreamData(streamID uint64, body []byte, endOfStream bool) bool // SendHttpStreamTrailers sends trailers on an existing HTTP stream. - // @Param streamID the ID of the HTTP stream. - // @Param trailers the HTTP trailers to be sent with the request. // - // @Return whether the trailers were successfully sent. + // Returns the trailers were successfully sent. // // NOTE: This method should only be called during OnRequest* or OnResponse* callbacks or // scheduled functions via the Scheduler. By this way we can ensure this is only be called @@ -738,7 +639,6 @@ type HttpFilterHandle interface { SendHttpStreamTrailers(streamID uint64, trailers [][2]string) bool // ResetHttpStream resets an existing HTTP stream. - // @Param streamID the ID of the HTTP stream. // // NOTE: This method should only be called during OnRequest* or OnResponse* callbacks or // scheduled functions via the Scheduler. By this way we can ensure this is only be called @@ -746,80 +646,139 @@ type HttpFilterHandle interface { ResetHttpStream(streamID uint64) // SetDownstreamWatermarkCallbacks sets the downstream watermark callbacks for the stream. - // @Param callbacks the downstream watermark callbacks. SetDownstreamWatermarkCallbacks(callbacks DownstreamWatermarkCallbacks) // ClearDownstreamWatermarkCallbacks unsets the downstream watermark callbacks for the stream. ClearDownstreamWatermarkCallbacks() // RecordValue records the given value to the histogram metric. - // @Param id the histogram metric id. - // @Param value the value to be recorded. - // @Param tagsValues the optional tag values associated with the metric. The order and size // of the tag values must match the tag keys defined when the metric was created. RecordHistogramValue(id MetricID, value uint64, tagsValues ...string) MetricsResult // SetValue sets the given value to the gauge metric. - // @Param id the gauge metric id. - // @Param value the value to be set. - // @Param tagsValues the optional tag values associated with the metric. The order and size // of the tag values must match the tag keys defined when the metric was created. SetGaugeValue(id MetricID, value uint64, tagsValues ...string) MetricsResult // IncrementGaugeValue adds the given value to the gauge metric. - // @Param id the gauge metric id. - // @Param value the value to be added. - // @Param tagsValues the optional tag values associated with the metric. The order and size // of the tag values must match the tag keys defined when the metric was created. IncrementGaugeValue(id MetricID, value uint64, tagsValues ...string) MetricsResult // DecrementGaugeValue subtracts the given value from the gauge metric. - // @Param id the gauge metric id. - // @Param value the value to be subtracted. - // @Param tagsValues the optional tag values associated with the metric. The order and size // of the tag values must match the tag keys defined when the metric was created. DecrementGaugeValue(id MetricID, value uint64, tagsValues ...string) MetricsResult // IncrementCounterValue adds the given value to the counter metric. - // @Param id the counter metric id. - // @Param value the value to be added. - // @Param tagsValues the optional tag values associated with the metric. The order and size // of the tag values must match the tag keys defined when the metric was created. IncrementCounterValue(id MetricID, value uint64, tagsValues ...string) MetricsResult -} -type MetricID uint64 -type MetricsResult uint32 + // GetWorkerIndex returns the worker thread index assigned to the current HTTP filter. + // This can be used by the module to manage worker-specific resources. + GetWorkerIndex() uint32 + + // GetFilterStateTyped retrieves the serialized bytes of a typed filter state object stored + // under the given key. Unlike GetFilterState, this calls serializeAsString on the registered + // typed object, so it works for any filter state object type (not just StringAccessor). + // Returns serialized value if found, otherwise an empty UnsafeEnvoyBuffer and false. + // NOTE: The memory of the underlying data may not be managed by Go GC. Copy the data if you + // need to keep it past the current callback. + GetFilterStateTyped(key string) (UnsafeEnvoyBuffer, bool) -const ( - MetricsSuccess MetricsResult = iota - MetricsNotFound - MetricsInvalidTags - MetricsFrozen -) + // SetFilterStateTyped sets the typed filter state value stored under the given key. The key + // MUST match a registered ObjectFactory; the bytes are passed to createFromBytes on that + // factory. This is the form required for interop with built-in Envoy filters that read filter + // state as typed objects (e.g., tcp_proxy reading PerConnectionCluster). + // Returns if the operation was successful, false otherwise (e.g., no factory registered + // for the key, factory failed to create the object, or the key is read-only). + SetFilterStateTyped(key string, value []byte) bool + + // SetSocketOptionInt sets an integer-valued socket option on the upstream or downstream + // connection associated with the stream. + // downstream sockets. + // Returns if the operation was successful, false otherwise. + SetSocketOptionInt(level, name int64, state SocketOptionState, direction SocketDirection, value int64) bool + + // SetSocketOptionBytes sets a bytes-valued socket option on the upstream or downstream + // connection associated with the stream. + // Returns if the operation was successful, false otherwise. + SetSocketOptionBytes(level, name int64, state SocketOptionState, direction SocketDirection, value []byte) bool + + // GetSocketOptionInt retrieves the integer value of a socket option. + // Returns value and true if found, otherwise 0 and false. + GetSocketOptionInt(level, name int64, state SocketOptionState, direction SocketDirection) (int64, bool) + + // GetSocketOptionBytes retrieves the bytes value of a socket option. The buffer is owned by + // Envoy and remains valid until the filter is destroyed. + // Returns value and true if found, otherwise an empty UnsafeEnvoyBuffer and false. + // NOTE: The memory of the underlying data may not be managed by Go GC. Copy the data if you + // need to keep it past the current callback. + GetSocketOptionBytes(level, name int64, state SocketOptionState, direction SocketDirection) (UnsafeEnvoyBuffer, bool) + + // GetBufferLimit returns the current per-stream body buffer limit in bytes. A limit of 0 + // indicates no limit is applied. + GetBufferLimit() uint64 + + // SetBufferLimit sets the per-stream body buffer limit. It is recommended (but not required) + // that filters only INCREASE the limit, to avoid conflicting with the buffer requirements of + // other filters in the chain. + SetBufferLimit(limit uint64) + + // GetActiveSpan returns the active tracing span for the stream, or nil if tracing is disabled + // or no span is available. The returned Span is owned by Envoy; do not Finish it. Use + // Span.SpawnChild to create module-owned child spans. + GetActiveSpan() Span + + // GetClusterName returns the name of the cluster the current request is routed to. + // Returns cluster name and true if found, otherwise an empty UnsafeEnvoyBuffer and false. + // NOTE: The memory of the underlying data may not be managed by Go GC. Copy the data if you + // need to keep it past the current callback. + GetClusterName() (UnsafeEnvoyBuffer, bool) + + // GetClusterHostCounts returns the host counts for the routed cluster at the given priority. + // Returns host counts and true if successful, otherwise a zero-valued struct and false. + GetClusterHostCounts(priority uint32) (ClusterHostCounts, bool) + + // SetUpstreamOverrideHost sets a host that the upstream load balancer should select first if + // it exists in the routed cluster. This is useful for sticky sessions or host affinity. + // false, normal load balancing is used as a fallback. + // Returns if the override was set successfully, false if the host address was invalid. + SetUpstreamOverrideHost(host string, strict bool) bool + + // ResetStream resets the HTTP stream with the given reason and optional details. After this + // call, no further filter callbacks will be invoked except OnDestroy. + ResetStream(reason HttpFilterStreamResetReason, details string) + + // SendGoAwayAndClose sends a GOAWAY frame to the downstream and closes the connection. If + // graceful is true, a graceful drain is initiated before closing. + SendGoAwayAndClose(graceful bool) + + // RecreateStream recreates the HTTP stream, optionally with new headers (or with the original + // headers if headers is nil). Useful for internal redirects or request retries. After a + // successful call, the current filter chain is destroyed and the filter SHOULD return Stop + // from the current callback. + // Returns if recreation was initiated, false otherwise (e.g., the request body has not + // been fully received yet). + RecreateStream(headers [][2]string) bool +} +// HttpFilterConfigHandle is the per-filter-config handle exposed to HttpFilterConfig +// implementations. It supports config-scoped logging, metric definition, and async I/O via +// HttpCallout / StartHttpStream from the main thread. type HttpFilterConfigHandle interface { // Log will log the given message via the host environment's logging mechanism. Log(level LogLevel, format string, args ...any) // DefineHistogram creates a histogram metric with the given name, and tag keys. - // @Param name the name of the metric. - // @Param tagKeys the optional tag keys for the metric. - // @Return the histogram metric id. This metric can never be used after the plugin + // Returns histogram metric id. This metric can never be used after the plugin // config is unloaded. DefineHistogram(name string, tagKeys ...string) (MetricID, MetricsResult) // DefineGauge creates a gauge metric with the given name, description, and tag keys. - // @Param name the name of the metric. - // @Param tagKeys the optional tag keys for the metric. - // @Return the gauge metric id. This metric can never be used after the plugin + // Returns gauge metric id. This metric can never be used after the plugin // config is unloaded. DefineGauge(name string, tagKeys ...string) (MetricID, MetricsResult) // DefineCounter creates a counter metric with the given name, description, and tag keys. - // @Param name the name of the metric. - // @Param tagKeys the optional tag keys for the metric. - // @Return the counter metric id. This metric can never be used after the plugin + // Returns counter metric id. This metric can never be used after the plugin // config is unloaded. DefineCounter(name string, tagKeys ...string) (MetricID, MetricsResult) @@ -827,43 +786,26 @@ type HttpFilterConfigHandle interface { // The call is asynchronous, and the response will be delivered via the provided callback. // This is similar to HttpFilterHandle.HttpCallout but runs on the main thread rather than // the worker thread. - // @Param cluster the cluster (target) name to which the HTTP call will be made. - // @Param headers the HTTP headers to be sent with the request. - // @Param body the HTTP body to be sent with the request. - // @Param timeoutMs the timeout in milliseconds for the HTTP call. - // @Param callback the callback function to be invoked when the response is received. - // @Return the result of the HTTP callout initialization and the callout ID. + // Returns result of the HTTP callout initialization and the callout ID. HttpCallout(cluster string, headers [][2]string, body []byte, timeoutMs uint64, cb HttpCalloutCallback) (HttpCalloutInitResult, uint64) // StartHttpStream starts a new HTTP stream to an external service from the config context. // The stream is asynchronous, and the response will be delivered via the provided callback. // This is similar to HttpFilterHandle.StartHttpStream but runs on the main thread. - // @Param cluster the cluster (target) name. - // @Param headers the initial HTTP headers. - // @Param body the initial HTTP body. - // @Param endOfStream whether this is the end of the stream. - // @Param timeoutMs the timeout in milliseconds. - // @Param callback the callback interface to handle the stream events. - // @Return the result of the HTTP stream initialization and the stream ID. + // Returns result of the HTTP stream initialization and the stream ID. StartHttpStream(cluster string, headers [][2]string, body []byte, endOfStream bool, timeoutMs uint64, cb HttpStreamCallback) (HttpCalloutInitResult, uint64) // SendHttpStreamData sends data on an existing HTTP stream started via StartHttpStream. - // @Param streamID the ID of the HTTP stream. - // @Param body the HTTP body to be sent. - // @Param endOfStream whether this is the end of the stream. - // @Return whether the data was successfully sent. + // Returns the data was successfully sent. SendHttpStreamData(streamID uint64, body []byte, endOfStream bool) bool // SendHttpStreamTrailers sends trailers on an existing HTTP stream started via StartHttpStream. - // @Param streamID the ID of the HTTP stream. - // @Param trailers the HTTP trailers to be sent. - // @Return whether the trailers were successfully sent. + // Returns the trailers were successfully sent. SendHttpStreamTrailers(streamID uint64, trailers [][2]string) bool // ResetHttpStream resets an existing HTTP stream started via StartHttpStream. - // @Param streamID the ID of the HTTP stream. ResetHttpStream(streamID uint64) // GetScheduler retrieves a scheduler for deferred task execution in the config context. diff --git a/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_api.go b/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_api.go deleted file mode 100644 index 34dae5915c643..0000000000000 --- a/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_api.go +++ /dev/null @@ -1,267 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: api.go -// -// Generated by this command: -// -// mockgen -source=api.go -destination=mocks/mock_api.go -package=mocks -// - -// Package mocks is a generated GoMock package. -package mocks - -import ( - reflect "reflect" - - shared "github.com/envoyproxy/envoy/source/extensions/dynamic_modules/sdk/go/shared" - gomock "go.uber.org/mock/gomock" -) - -// MockHttpFilter is a mock of HttpFilter interface. -type MockHttpFilter struct { - ctrl *gomock.Controller - recorder *MockHttpFilterMockRecorder - isgomock struct{} -} - -// MockHttpFilterMockRecorder is the mock recorder for MockHttpFilter. -type MockHttpFilterMockRecorder struct { - mock *MockHttpFilter -} - -// NewMockHttpFilter creates a new mock instance. -func NewMockHttpFilter(ctrl *gomock.Controller) *MockHttpFilter { - mock := &MockHttpFilter{ctrl: ctrl} - mock.recorder = &MockHttpFilterMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockHttpFilter) EXPECT() *MockHttpFilterMockRecorder { - return m.recorder -} - -// OnDestroy mocks base method. -func (m *MockHttpFilter) OnDestroy() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "OnDestroy") -} - -// OnDestroy indicates an expected call of OnDestroy. -func (mr *MockHttpFilterMockRecorder) OnDestroy() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnDestroy", reflect.TypeOf((*MockHttpFilter)(nil).OnDestroy)) -} - -// OnLocalReply mocks base method. -func (m *MockHttpFilter) OnLocalReply(responseCode uint32, details shared.UnsafeEnvoyBuffer, resetImminent bool) shared.LocalReplyStatus { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnLocalReply", responseCode, details, resetImminent) - ret0, _ := ret[0].(shared.LocalReplyStatus) - return ret0 -} - -// OnLocalReply indicates an expected call of OnLocalReply. -func (mr *MockHttpFilterMockRecorder) OnLocalReply(responseCode, details, resetImminent any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnLocalReply", reflect.TypeOf((*MockHttpFilter)(nil).OnLocalReply), responseCode, details, resetImminent) -} - -// OnRequestBody mocks base method. -func (m *MockHttpFilter) OnRequestBody(body shared.BodyBuffer, endOfStream bool) shared.BodyStatus { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnRequestBody", body, endOfStream) - ret0, _ := ret[0].(shared.BodyStatus) - return ret0 -} - -// OnRequestBody indicates an expected call of OnRequestBody. -func (mr *MockHttpFilterMockRecorder) OnRequestBody(body, endOfStream any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnRequestBody", reflect.TypeOf((*MockHttpFilter)(nil).OnRequestBody), body, endOfStream) -} - -// OnRequestHeaders mocks base method. -func (m *MockHttpFilter) OnRequestHeaders(headers shared.HeaderMap, endOfStream bool) shared.HeadersStatus { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnRequestHeaders", headers, endOfStream) - ret0, _ := ret[0].(shared.HeadersStatus) - return ret0 -} - -// OnRequestHeaders indicates an expected call of OnRequestHeaders. -func (mr *MockHttpFilterMockRecorder) OnRequestHeaders(headers, endOfStream any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnRequestHeaders", reflect.TypeOf((*MockHttpFilter)(nil).OnRequestHeaders), headers, endOfStream) -} - -// OnRequestTrailers mocks base method. -func (m *MockHttpFilter) OnRequestTrailers(trailers shared.HeaderMap) shared.TrailersStatus { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnRequestTrailers", trailers) - ret0, _ := ret[0].(shared.TrailersStatus) - return ret0 -} - -// OnRequestTrailers indicates an expected call of OnRequestTrailers. -func (mr *MockHttpFilterMockRecorder) OnRequestTrailers(trailers any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnRequestTrailers", reflect.TypeOf((*MockHttpFilter)(nil).OnRequestTrailers), trailers) -} - -// OnResponseBody mocks base method. -func (m *MockHttpFilter) OnResponseBody(body shared.BodyBuffer, endOfStream bool) shared.BodyStatus { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnResponseBody", body, endOfStream) - ret0, _ := ret[0].(shared.BodyStatus) - return ret0 -} - -// OnResponseBody indicates an expected call of OnResponseBody. -func (mr *MockHttpFilterMockRecorder) OnResponseBody(body, endOfStream any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnResponseBody", reflect.TypeOf((*MockHttpFilter)(nil).OnResponseBody), body, endOfStream) -} - -// OnResponseHeaders mocks base method. -func (m *MockHttpFilter) OnResponseHeaders(headers shared.HeaderMap, endOfStream bool) shared.HeadersStatus { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnResponseHeaders", headers, endOfStream) - ret0, _ := ret[0].(shared.HeadersStatus) - return ret0 -} - -// OnResponseHeaders indicates an expected call of OnResponseHeaders. -func (mr *MockHttpFilterMockRecorder) OnResponseHeaders(headers, endOfStream any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnResponseHeaders", reflect.TypeOf((*MockHttpFilter)(nil).OnResponseHeaders), headers, endOfStream) -} - -// OnResponseTrailers mocks base method. -func (m *MockHttpFilter) OnResponseTrailers(trailers shared.HeaderMap) shared.TrailersStatus { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnResponseTrailers", trailers) - ret0, _ := ret[0].(shared.TrailersStatus) - return ret0 -} - -// OnResponseTrailers indicates an expected call of OnResponseTrailers. -func (mr *MockHttpFilterMockRecorder) OnResponseTrailers(trailers any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnResponseTrailers", reflect.TypeOf((*MockHttpFilter)(nil).OnResponseTrailers), trailers) -} - -// OnStreamComplete mocks base method. -func (m *MockHttpFilter) OnStreamComplete() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "OnStreamComplete") -} - -// OnStreamComplete indicates an expected call of OnStreamComplete. -func (mr *MockHttpFilterMockRecorder) OnStreamComplete() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnStreamComplete", reflect.TypeOf((*MockHttpFilter)(nil).OnStreamComplete)) -} - -// MockHttpFilterFactory is a mock of HttpFilterFactory interface. -type MockHttpFilterFactory struct { - ctrl *gomock.Controller - recorder *MockHttpFilterFactoryMockRecorder - isgomock struct{} -} - -// MockHttpFilterFactoryMockRecorder is the mock recorder for MockHttpFilterFactory. -type MockHttpFilterFactoryMockRecorder struct { - mock *MockHttpFilterFactory -} - -// NewMockHttpFilterFactory creates a new mock instance. -func NewMockHttpFilterFactory(ctrl *gomock.Controller) *MockHttpFilterFactory { - mock := &MockHttpFilterFactory{ctrl: ctrl} - mock.recorder = &MockHttpFilterFactoryMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockHttpFilterFactory) EXPECT() *MockHttpFilterFactoryMockRecorder { - return m.recorder -} - -// Create mocks base method. -func (m *MockHttpFilterFactory) Create(handle shared.HttpFilterHandle) shared.HttpFilter { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Create", handle) - ret0, _ := ret[0].(shared.HttpFilter) - return ret0 -} - -// Create indicates an expected call of Create. -func (mr *MockHttpFilterFactoryMockRecorder) Create(handle any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockHttpFilterFactory)(nil).Create), handle) -} - -// OnDestroy mocks base method. -func (m *MockHttpFilterFactory) OnDestroy() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "OnDestroy") -} - -// OnDestroy indicates an expected call of OnDestroy. -func (mr *MockHttpFilterFactoryMockRecorder) OnDestroy() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnDestroy", reflect.TypeOf((*MockHttpFilterFactory)(nil).OnDestroy)) -} - -// MockHttpFilterConfigFactory is a mock of HttpFilterConfigFactory interface. -type MockHttpFilterConfigFactory struct { - ctrl *gomock.Controller - recorder *MockHttpFilterConfigFactoryMockRecorder - isgomock struct{} -} - -// MockHttpFilterConfigFactoryMockRecorder is the mock recorder for MockHttpFilterConfigFactory. -type MockHttpFilterConfigFactoryMockRecorder struct { - mock *MockHttpFilterConfigFactory -} - -// NewMockHttpFilterConfigFactory creates a new mock instance. -func NewMockHttpFilterConfigFactory(ctrl *gomock.Controller) *MockHttpFilterConfigFactory { - mock := &MockHttpFilterConfigFactory{ctrl: ctrl} - mock.recorder = &MockHttpFilterConfigFactoryMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockHttpFilterConfigFactory) EXPECT() *MockHttpFilterConfigFactoryMockRecorder { - return m.recorder -} - -// Create mocks base method. -func (m *MockHttpFilterConfigFactory) Create(handle shared.HttpFilterConfigHandle, unparsedConfig []byte) (shared.HttpFilterFactory, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Create", handle, unparsedConfig) - ret0, _ := ret[0].(shared.HttpFilterFactory) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Create indicates an expected call of Create. -func (mr *MockHttpFilterConfigFactoryMockRecorder) Create(handle, unparsedConfig any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockHttpFilterConfigFactory)(nil).Create), handle, unparsedConfig) -} - -// CreatePerRoute mocks base method. -func (m *MockHttpFilterConfigFactory) CreatePerRoute(unparsedConfig []byte) (any, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreatePerRoute", unparsedConfig) - ret0, _ := ret[0].(any) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CreatePerRoute indicates an expected call of CreatePerRoute. -func (mr *MockHttpFilterConfigFactoryMockRecorder) CreatePerRoute(unparsedConfig any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreatePerRoute", reflect.TypeOf((*MockHttpFilterConfigFactory)(nil).CreatePerRoute), unparsedConfig) -} diff --git a/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_base.go b/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_http.go similarity index 88% rename from source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_base.go rename to source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_http.go index 0793e6d3fcdfc..e3b7aa96e9b9c 100644 --- a/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_base.go +++ b/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_http.go @@ -1,9 +1,9 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: base.go +// Source: http.go // // Generated by this command: // -// mockgen -source=base.go -destination=mocks/mock_base.go -package=mocks +// mockgen -source=http.go -destination=mocks/mock_http.go -package=mocks // // Package mocks is a generated GoMock package. @@ -16,6 +16,256 @@ import ( gomock "go.uber.org/mock/gomock" ) +// MockHttpFilter is a mock of HttpFilter interface. +type MockHttpFilter struct { + ctrl *gomock.Controller + recorder *MockHttpFilterMockRecorder + isgomock struct{} +} + +// MockHttpFilterMockRecorder is the mock recorder for MockHttpFilter. +type MockHttpFilterMockRecorder struct { + mock *MockHttpFilter +} + +// NewMockHttpFilter creates a new mock instance. +func NewMockHttpFilter(ctrl *gomock.Controller) *MockHttpFilter { + mock := &MockHttpFilter{ctrl: ctrl} + mock.recorder = &MockHttpFilterMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockHttpFilter) EXPECT() *MockHttpFilterMockRecorder { + return m.recorder +} + +// OnDestroy mocks base method. +func (m *MockHttpFilter) OnDestroy() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OnDestroy") +} + +// OnDestroy indicates an expected call of OnDestroy. +func (mr *MockHttpFilterMockRecorder) OnDestroy() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnDestroy", reflect.TypeOf((*MockHttpFilter)(nil).OnDestroy)) +} + +// OnLocalReply mocks base method. +func (m *MockHttpFilter) OnLocalReply(responseCode uint32, details shared.UnsafeEnvoyBuffer, resetImminent bool) shared.LocalReplyStatus { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnLocalReply", responseCode, details, resetImminent) + ret0, _ := ret[0].(shared.LocalReplyStatus) + return ret0 +} + +// OnLocalReply indicates an expected call of OnLocalReply. +func (mr *MockHttpFilterMockRecorder) OnLocalReply(responseCode, details, resetImminent any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnLocalReply", reflect.TypeOf((*MockHttpFilter)(nil).OnLocalReply), responseCode, details, resetImminent) +} + +// OnRequestBody mocks base method. +func (m *MockHttpFilter) OnRequestBody(body shared.BodyBuffer, endOfStream bool) shared.BodyStatus { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnRequestBody", body, endOfStream) + ret0, _ := ret[0].(shared.BodyStatus) + return ret0 +} + +// OnRequestBody indicates an expected call of OnRequestBody. +func (mr *MockHttpFilterMockRecorder) OnRequestBody(body, endOfStream any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnRequestBody", reflect.TypeOf((*MockHttpFilter)(nil).OnRequestBody), body, endOfStream) +} + +// OnRequestHeaders mocks base method. +func (m *MockHttpFilter) OnRequestHeaders(headers shared.HeaderMap, endOfStream bool) shared.HeadersStatus { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnRequestHeaders", headers, endOfStream) + ret0, _ := ret[0].(shared.HeadersStatus) + return ret0 +} + +// OnRequestHeaders indicates an expected call of OnRequestHeaders. +func (mr *MockHttpFilterMockRecorder) OnRequestHeaders(headers, endOfStream any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnRequestHeaders", reflect.TypeOf((*MockHttpFilter)(nil).OnRequestHeaders), headers, endOfStream) +} + +// OnRequestTrailers mocks base method. +func (m *MockHttpFilter) OnRequestTrailers(trailers shared.HeaderMap) shared.TrailersStatus { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnRequestTrailers", trailers) + ret0, _ := ret[0].(shared.TrailersStatus) + return ret0 +} + +// OnRequestTrailers indicates an expected call of OnRequestTrailers. +func (mr *MockHttpFilterMockRecorder) OnRequestTrailers(trailers any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnRequestTrailers", reflect.TypeOf((*MockHttpFilter)(nil).OnRequestTrailers), trailers) +} + +// OnResponseBody mocks base method. +func (m *MockHttpFilter) OnResponseBody(body shared.BodyBuffer, endOfStream bool) shared.BodyStatus { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnResponseBody", body, endOfStream) + ret0, _ := ret[0].(shared.BodyStatus) + return ret0 +} + +// OnResponseBody indicates an expected call of OnResponseBody. +func (mr *MockHttpFilterMockRecorder) OnResponseBody(body, endOfStream any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnResponseBody", reflect.TypeOf((*MockHttpFilter)(nil).OnResponseBody), body, endOfStream) +} + +// OnResponseHeaders mocks base method. +func (m *MockHttpFilter) OnResponseHeaders(headers shared.HeaderMap, endOfStream bool) shared.HeadersStatus { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnResponseHeaders", headers, endOfStream) + ret0, _ := ret[0].(shared.HeadersStatus) + return ret0 +} + +// OnResponseHeaders indicates an expected call of OnResponseHeaders. +func (mr *MockHttpFilterMockRecorder) OnResponseHeaders(headers, endOfStream any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnResponseHeaders", reflect.TypeOf((*MockHttpFilter)(nil).OnResponseHeaders), headers, endOfStream) +} + +// OnResponseTrailers mocks base method. +func (m *MockHttpFilter) OnResponseTrailers(trailers shared.HeaderMap) shared.TrailersStatus { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnResponseTrailers", trailers) + ret0, _ := ret[0].(shared.TrailersStatus) + return ret0 +} + +// OnResponseTrailers indicates an expected call of OnResponseTrailers. +func (mr *MockHttpFilterMockRecorder) OnResponseTrailers(trailers any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnResponseTrailers", reflect.TypeOf((*MockHttpFilter)(nil).OnResponseTrailers), trailers) +} + +// OnStreamComplete mocks base method. +func (m *MockHttpFilter) OnStreamComplete() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OnStreamComplete") +} + +// OnStreamComplete indicates an expected call of OnStreamComplete. +func (mr *MockHttpFilterMockRecorder) OnStreamComplete() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnStreamComplete", reflect.TypeOf((*MockHttpFilter)(nil).OnStreamComplete)) +} + +// MockHttpFilterFactory is a mock of HttpFilterFactory interface. +type MockHttpFilterFactory struct { + ctrl *gomock.Controller + recorder *MockHttpFilterFactoryMockRecorder + isgomock struct{} +} + +// MockHttpFilterFactoryMockRecorder is the mock recorder for MockHttpFilterFactory. +type MockHttpFilterFactoryMockRecorder struct { + mock *MockHttpFilterFactory +} + +// NewMockHttpFilterFactory creates a new mock instance. +func NewMockHttpFilterFactory(ctrl *gomock.Controller) *MockHttpFilterFactory { + mock := &MockHttpFilterFactory{ctrl: ctrl} + mock.recorder = &MockHttpFilterFactoryMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockHttpFilterFactory) EXPECT() *MockHttpFilterFactoryMockRecorder { + return m.recorder +} + +// Create mocks base method. +func (m *MockHttpFilterFactory) Create(handle shared.HttpFilterHandle) shared.HttpFilter { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Create", handle) + ret0, _ := ret[0].(shared.HttpFilter) + return ret0 +} + +// Create indicates an expected call of Create. +func (mr *MockHttpFilterFactoryMockRecorder) Create(handle any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockHttpFilterFactory)(nil).Create), handle) +} + +// OnDestroy mocks base method. +func (m *MockHttpFilterFactory) OnDestroy() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OnDestroy") +} + +// OnDestroy indicates an expected call of OnDestroy. +func (mr *MockHttpFilterFactoryMockRecorder) OnDestroy() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnDestroy", reflect.TypeOf((*MockHttpFilterFactory)(nil).OnDestroy)) +} + +// MockHttpFilterConfigFactory is a mock of HttpFilterConfigFactory interface. +type MockHttpFilterConfigFactory struct { + ctrl *gomock.Controller + recorder *MockHttpFilterConfigFactoryMockRecorder + isgomock struct{} +} + +// MockHttpFilterConfigFactoryMockRecorder is the mock recorder for MockHttpFilterConfigFactory. +type MockHttpFilterConfigFactoryMockRecorder struct { + mock *MockHttpFilterConfigFactory +} + +// NewMockHttpFilterConfigFactory creates a new mock instance. +func NewMockHttpFilterConfigFactory(ctrl *gomock.Controller) *MockHttpFilterConfigFactory { + mock := &MockHttpFilterConfigFactory{ctrl: ctrl} + mock.recorder = &MockHttpFilterConfigFactoryMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockHttpFilterConfigFactory) EXPECT() *MockHttpFilterConfigFactoryMockRecorder { + return m.recorder +} + +// Create mocks base method. +func (m *MockHttpFilterConfigFactory) Create(handle shared.HttpFilterConfigHandle, unparsedConfig []byte) (shared.HttpFilterFactory, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Create", handle, unparsedConfig) + ret0, _ := ret[0].(shared.HttpFilterFactory) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Create indicates an expected call of Create. +func (mr *MockHttpFilterConfigFactoryMockRecorder) Create(handle, unparsedConfig any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockHttpFilterConfigFactory)(nil).Create), handle, unparsedConfig) +} + +// CreatePerRoute mocks base method. +func (m *MockHttpFilterConfigFactory) CreatePerRoute(unparsedConfig []byte) (any, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreatePerRoute", unparsedConfig) + ret0, _ := ret[0].(any) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreatePerRoute indicates an expected call of CreatePerRoute. +func (mr *MockHttpFilterConfigFactoryMockRecorder) CreatePerRoute(unparsedConfig any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreatePerRoute", reflect.TypeOf((*MockHttpFilterConfigFactory)(nil).CreatePerRoute), unparsedConfig) +} + // MockBodyBuffer is a mock of BodyBuffer interface. type MockBodyBuffer struct { ctrl *gomock.Controller @@ -194,210 +444,6 @@ func (mr *MockHeaderMapMockRecorder) Set(key, value any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Set", reflect.TypeOf((*MockHeaderMap)(nil).Set), key, value) } -// MockHttpCalloutCallback is a mock of HttpCalloutCallback interface. -type MockHttpCalloutCallback struct { - ctrl *gomock.Controller - recorder *MockHttpCalloutCallbackMockRecorder - isgomock struct{} -} - -// MockHttpCalloutCallbackMockRecorder is the mock recorder for MockHttpCalloutCallback. -type MockHttpCalloutCallbackMockRecorder struct { - mock *MockHttpCalloutCallback -} - -// NewMockHttpCalloutCallback creates a new mock instance. -func NewMockHttpCalloutCallback(ctrl *gomock.Controller) *MockHttpCalloutCallback { - mock := &MockHttpCalloutCallback{ctrl: ctrl} - mock.recorder = &MockHttpCalloutCallbackMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockHttpCalloutCallback) EXPECT() *MockHttpCalloutCallbackMockRecorder { - return m.recorder -} - -// OnHttpCalloutDone mocks base method. -func (m *MockHttpCalloutCallback) OnHttpCalloutDone(calloutID uint64, result shared.HttpCalloutResult, headers [][2]shared.UnsafeEnvoyBuffer, body []shared.UnsafeEnvoyBuffer) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "OnHttpCalloutDone", calloutID, result, headers, body) -} - -// OnHttpCalloutDone indicates an expected call of OnHttpCalloutDone. -func (mr *MockHttpCalloutCallbackMockRecorder) OnHttpCalloutDone(calloutID, result, headers, body any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnHttpCalloutDone", reflect.TypeOf((*MockHttpCalloutCallback)(nil).OnHttpCalloutDone), calloutID, result, headers, body) -} - -// MockHttpStreamCallback is a mock of HttpStreamCallback interface. -type MockHttpStreamCallback struct { - ctrl *gomock.Controller - recorder *MockHttpStreamCallbackMockRecorder - isgomock struct{} -} - -// MockHttpStreamCallbackMockRecorder is the mock recorder for MockHttpStreamCallback. -type MockHttpStreamCallbackMockRecorder struct { - mock *MockHttpStreamCallback -} - -// NewMockHttpStreamCallback creates a new mock instance. -func NewMockHttpStreamCallback(ctrl *gomock.Controller) *MockHttpStreamCallback { - mock := &MockHttpStreamCallback{ctrl: ctrl} - mock.recorder = &MockHttpStreamCallbackMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockHttpStreamCallback) EXPECT() *MockHttpStreamCallbackMockRecorder { - return m.recorder -} - -// OnHttpStreamComplete mocks base method. -func (m *MockHttpStreamCallback) OnHttpStreamComplete(streamID uint64) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "OnHttpStreamComplete", streamID) -} - -// OnHttpStreamComplete indicates an expected call of OnHttpStreamComplete. -func (mr *MockHttpStreamCallbackMockRecorder) OnHttpStreamComplete(streamID any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnHttpStreamComplete", reflect.TypeOf((*MockHttpStreamCallback)(nil).OnHttpStreamComplete), streamID) -} - -// OnHttpStreamData mocks base method. -func (m *MockHttpStreamCallback) OnHttpStreamData(streamID uint64, body []shared.UnsafeEnvoyBuffer, endStream bool) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "OnHttpStreamData", streamID, body, endStream) -} - -// OnHttpStreamData indicates an expected call of OnHttpStreamData. -func (mr *MockHttpStreamCallbackMockRecorder) OnHttpStreamData(streamID, body, endStream any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnHttpStreamData", reflect.TypeOf((*MockHttpStreamCallback)(nil).OnHttpStreamData), streamID, body, endStream) -} - -// OnHttpStreamHeaders mocks base method. -func (m *MockHttpStreamCallback) OnHttpStreamHeaders(streamID uint64, headers [][2]shared.UnsafeEnvoyBuffer, endStream bool) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "OnHttpStreamHeaders", streamID, headers, endStream) -} - -// OnHttpStreamHeaders indicates an expected call of OnHttpStreamHeaders. -func (mr *MockHttpStreamCallbackMockRecorder) OnHttpStreamHeaders(streamID, headers, endStream any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnHttpStreamHeaders", reflect.TypeOf((*MockHttpStreamCallback)(nil).OnHttpStreamHeaders), streamID, headers, endStream) -} - -// OnHttpStreamReset mocks base method. -func (m *MockHttpStreamCallback) OnHttpStreamReset(streamID uint64, reason shared.HttpStreamResetReason) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "OnHttpStreamReset", streamID, reason) -} - -// OnHttpStreamReset indicates an expected call of OnHttpStreamReset. -func (mr *MockHttpStreamCallbackMockRecorder) OnHttpStreamReset(streamID, reason any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnHttpStreamReset", reflect.TypeOf((*MockHttpStreamCallback)(nil).OnHttpStreamReset), streamID, reason) -} - -// OnHttpStreamTrailers mocks base method. -func (m *MockHttpStreamCallback) OnHttpStreamTrailers(streamID uint64, trailers [][2]shared.UnsafeEnvoyBuffer) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "OnHttpStreamTrailers", streamID, trailers) -} - -// OnHttpStreamTrailers indicates an expected call of OnHttpStreamTrailers. -func (mr *MockHttpStreamCallbackMockRecorder) OnHttpStreamTrailers(streamID, trailers any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnHttpStreamTrailers", reflect.TypeOf((*MockHttpStreamCallback)(nil).OnHttpStreamTrailers), streamID, trailers) -} - -// MockScheduler is a mock of Scheduler interface. -type MockScheduler struct { - ctrl *gomock.Controller - recorder *MockSchedulerMockRecorder - isgomock struct{} -} - -// MockSchedulerMockRecorder is the mock recorder for MockScheduler. -type MockSchedulerMockRecorder struct { - mock *MockScheduler -} - -// NewMockScheduler creates a new mock instance. -func NewMockScheduler(ctrl *gomock.Controller) *MockScheduler { - mock := &MockScheduler{ctrl: ctrl} - mock.recorder = &MockSchedulerMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockScheduler) EXPECT() *MockSchedulerMockRecorder { - return m.recorder -} - -// Schedule mocks base method. -func (m *MockScheduler) Schedule(arg0 func()) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "Schedule", arg0) -} - -// Schedule indicates an expected call of Schedule. -func (mr *MockSchedulerMockRecorder) Schedule(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Schedule", reflect.TypeOf((*MockScheduler)(nil).Schedule), arg0) -} - -// MockDownstreamWatermarkCallbacks is a mock of DownstreamWatermarkCallbacks interface. -type MockDownstreamWatermarkCallbacks struct { - ctrl *gomock.Controller - recorder *MockDownstreamWatermarkCallbacksMockRecorder - isgomock struct{} -} - -// MockDownstreamWatermarkCallbacksMockRecorder is the mock recorder for MockDownstreamWatermarkCallbacks. -type MockDownstreamWatermarkCallbacksMockRecorder struct { - mock *MockDownstreamWatermarkCallbacks -} - -// NewMockDownstreamWatermarkCallbacks creates a new mock instance. -func NewMockDownstreamWatermarkCallbacks(ctrl *gomock.Controller) *MockDownstreamWatermarkCallbacks { - mock := &MockDownstreamWatermarkCallbacks{ctrl: ctrl} - mock.recorder = &MockDownstreamWatermarkCallbacksMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockDownstreamWatermarkCallbacks) EXPECT() *MockDownstreamWatermarkCallbacksMockRecorder { - return m.recorder -} - -// OnAboveWriteBufferHighWatermark mocks base method. -func (m *MockDownstreamWatermarkCallbacks) OnAboveWriteBufferHighWatermark() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "OnAboveWriteBufferHighWatermark") -} - -// OnAboveWriteBufferHighWatermark indicates an expected call of OnAboveWriteBufferHighWatermark. -func (mr *MockDownstreamWatermarkCallbacksMockRecorder) OnAboveWriteBufferHighWatermark() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnAboveWriteBufferHighWatermark", reflect.TypeOf((*MockDownstreamWatermarkCallbacks)(nil).OnAboveWriteBufferHighWatermark)) -} - -// OnBelowWriteBufferLowWatermark mocks base method. -func (m *MockDownstreamWatermarkCallbacks) OnBelowWriteBufferLowWatermark() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "OnBelowWriteBufferLowWatermark") -} - -// OnBelowWriteBufferLowWatermark indicates an expected call of OnBelowWriteBufferLowWatermark. -func (mr *MockDownstreamWatermarkCallbacksMockRecorder) OnBelowWriteBufferLowWatermark() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnBelowWriteBufferLowWatermark", reflect.TypeOf((*MockDownstreamWatermarkCallbacks)(nil).OnBelowWriteBufferLowWatermark)) -} - // MockSpan is a mock of Span interface. type MockSpan struct { ctrl *gomock.Controller @@ -528,17 +574,17 @@ func (mr *MockSpanMockRecorder) SetTag(key, value any) *gomock.Call { } // SpawnChild mocks base method. -func (m *MockSpan) SpawnChild(operation string) shared.ChildSpan { +func (m *MockSpan) SpawnChild(operationName string) shared.ChildSpan { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SpawnChild", operation) + ret := m.ctrl.Call(m, "SpawnChild", operationName) ret0, _ := ret[0].(shared.ChildSpan) return ret0 } // SpawnChild indicates an expected call of SpawnChild. -func (mr *MockSpanMockRecorder) SpawnChild(operation any) *gomock.Call { +func (mr *MockSpanMockRecorder) SpawnChild(operationName any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpawnChild", reflect.TypeOf((*MockSpan)(nil).SpawnChild), operation) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpawnChild", reflect.TypeOf((*MockSpan)(nil).SpawnChild), operationName) } // MockChildSpan is a mock of ChildSpan interface. @@ -577,51 +623,6 @@ func (mr *MockChildSpanMockRecorder) Finish() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Finish", reflect.TypeOf((*MockChildSpan)(nil).Finish)) } -// GetBaggage mocks base method. -func (m *MockChildSpan) GetBaggage(key string) (shared.UnsafeEnvoyBuffer, bool) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetBaggage", key) - ret0, _ := ret[0].(shared.UnsafeEnvoyBuffer) - ret1, _ := ret[1].(bool) - return ret0, ret1 -} - -// GetBaggage indicates an expected call of GetBaggage. -func (mr *MockChildSpanMockRecorder) GetBaggage(key any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBaggage", reflect.TypeOf((*MockChildSpan)(nil).GetBaggage), key) -} - -// GetSpanID mocks base method. -func (m *MockChildSpan) GetSpanID() (shared.UnsafeEnvoyBuffer, bool) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetSpanID") - ret0, _ := ret[0].(shared.UnsafeEnvoyBuffer) - ret1, _ := ret[1].(bool) - return ret0, ret1 -} - -// GetSpanID indicates an expected call of GetSpanID. -func (mr *MockChildSpanMockRecorder) GetSpanID() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSpanID", reflect.TypeOf((*MockChildSpan)(nil).GetSpanID)) -} - -// GetTraceID mocks base method. -func (m *MockChildSpan) GetTraceID() (shared.UnsafeEnvoyBuffer, bool) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetTraceID") - ret0, _ := ret[0].(shared.UnsafeEnvoyBuffer) - ret1, _ := ret[1].(bool) - return ret0, ret1 -} - -// GetTraceID indicates an expected call of GetTraceID. -func (mr *MockChildSpanMockRecorder) GetTraceID() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTraceID", reflect.TypeOf((*MockChildSpan)(nil).GetTraceID)) -} - // Log mocks base method. func (m *MockChildSpan) Log(event string) { m.ctrl.T.Helper() @@ -683,17 +684,65 @@ func (mr *MockChildSpanMockRecorder) SetTag(key, value any) *gomock.Call { } // SpawnChild mocks base method. -func (m *MockChildSpan) SpawnChild(operation string) shared.ChildSpan { +func (m *MockChildSpan) SpawnChild(operationName string) shared.ChildSpan { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SpawnChild", operation) + ret := m.ctrl.Call(m, "SpawnChild", operationName) ret0, _ := ret[0].(shared.ChildSpan) return ret0 } // SpawnChild indicates an expected call of SpawnChild. -func (mr *MockChildSpanMockRecorder) SpawnChild(operation any) *gomock.Call { +func (mr *MockChildSpanMockRecorder) SpawnChild(operationName any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpawnChild", reflect.TypeOf((*MockChildSpan)(nil).SpawnChild), operation) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpawnChild", reflect.TypeOf((*MockChildSpan)(nil).SpawnChild), operationName) +} + +// MockDownstreamWatermarkCallbacks is a mock of DownstreamWatermarkCallbacks interface. +type MockDownstreamWatermarkCallbacks struct { + ctrl *gomock.Controller + recorder *MockDownstreamWatermarkCallbacksMockRecorder + isgomock struct{} +} + +// MockDownstreamWatermarkCallbacksMockRecorder is the mock recorder for MockDownstreamWatermarkCallbacks. +type MockDownstreamWatermarkCallbacksMockRecorder struct { + mock *MockDownstreamWatermarkCallbacks +} + +// NewMockDownstreamWatermarkCallbacks creates a new mock instance. +func NewMockDownstreamWatermarkCallbacks(ctrl *gomock.Controller) *MockDownstreamWatermarkCallbacks { + mock := &MockDownstreamWatermarkCallbacks{ctrl: ctrl} + mock.recorder = &MockDownstreamWatermarkCallbacksMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockDownstreamWatermarkCallbacks) EXPECT() *MockDownstreamWatermarkCallbacksMockRecorder { + return m.recorder +} + +// OnAboveWriteBufferHighWatermark mocks base method. +func (m *MockDownstreamWatermarkCallbacks) OnAboveWriteBufferHighWatermark() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OnAboveWriteBufferHighWatermark") +} + +// OnAboveWriteBufferHighWatermark indicates an expected call of OnAboveWriteBufferHighWatermark. +func (mr *MockDownstreamWatermarkCallbacksMockRecorder) OnAboveWriteBufferHighWatermark() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnAboveWriteBufferHighWatermark", reflect.TypeOf((*MockDownstreamWatermarkCallbacks)(nil).OnAboveWriteBufferHighWatermark)) +} + +// OnBelowWriteBufferLowWatermark mocks base method. +func (m *MockDownstreamWatermarkCallbacks) OnBelowWriteBufferLowWatermark() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OnBelowWriteBufferLowWatermark") +} + +// OnBelowWriteBufferLowWatermark indicates an expected call of OnBelowWriteBufferLowWatermark. +func (mr *MockDownstreamWatermarkCallbacksMockRecorder) OnBelowWriteBufferLowWatermark() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnBelowWriteBufferLowWatermark", reflect.TypeOf((*MockDownstreamWatermarkCallbacks)(nil).OnBelowWriteBufferLowWatermark)) } // MockHttpFilterHandle is a mock of HttpFilterHandle interface. @@ -899,10 +948,10 @@ func (mr *MockHttpFilterHandleMockRecorder) GetAttributeBool(attributeID any) *g } // GetAttributeNumber mocks base method. -func (m *MockHttpFilterHandle) GetAttributeNumber(attributeID shared.AttributeID) (float64, bool) { +func (m *MockHttpFilterHandle) GetAttributeNumber(attributeID shared.AttributeID) (uint64, bool) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetAttributeNumber", attributeID) - ret0, _ := ret[0].(float64) + ret0, _ := ret[0].(uint64) ret1, _ := ret[1].(bool) return ret0, ret1 } diff --git a/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_network_api.go b/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_network_api.go new file mode 100644 index 0000000000000..a8cc08bd0de40 --- /dev/null +++ b/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_network_api.go @@ -0,0 +1,220 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: network_api.go +// +// Generated by this command: +// +// mockgen -source=network_api.go -destination=mocks/mock_network_api.go -package=mocks +// + +// Package mocks is a generated GoMock package. +package mocks + +import ( + reflect "reflect" + + shared "github.com/envoyproxy/envoy/source/extensions/dynamic_modules/sdk/go/shared" + gomock "go.uber.org/mock/gomock" +) + +// MockNetworkFilter is a mock of NetworkFilter interface. +type MockNetworkFilter struct { + ctrl *gomock.Controller + recorder *MockNetworkFilterMockRecorder + isgomock struct{} +} + +// MockNetworkFilterMockRecorder is the mock recorder for MockNetworkFilter. +type MockNetworkFilterMockRecorder struct { + mock *MockNetworkFilter +} + +// NewMockNetworkFilter creates a new mock instance. +func NewMockNetworkFilter(ctrl *gomock.Controller) *MockNetworkFilter { + mock := &MockNetworkFilter{ctrl: ctrl} + mock.recorder = &MockNetworkFilterMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockNetworkFilter) EXPECT() *MockNetworkFilterMockRecorder { + return m.recorder +} + +// OnAboveWriteBufferHighWatermark mocks base method. +func (m *MockNetworkFilter) OnAboveWriteBufferHighWatermark() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OnAboveWriteBufferHighWatermark") +} + +// OnAboveWriteBufferHighWatermark indicates an expected call of OnAboveWriteBufferHighWatermark. +func (mr *MockNetworkFilterMockRecorder) OnAboveWriteBufferHighWatermark() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnAboveWriteBufferHighWatermark", reflect.TypeOf((*MockNetworkFilter)(nil).OnAboveWriteBufferHighWatermark)) +} + +// OnBelowWriteBufferLowWatermark mocks base method. +func (m *MockNetworkFilter) OnBelowWriteBufferLowWatermark() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OnBelowWriteBufferLowWatermark") +} + +// OnBelowWriteBufferLowWatermark indicates an expected call of OnBelowWriteBufferLowWatermark. +func (mr *MockNetworkFilterMockRecorder) OnBelowWriteBufferLowWatermark() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnBelowWriteBufferLowWatermark", reflect.TypeOf((*MockNetworkFilter)(nil).OnBelowWriteBufferLowWatermark)) +} + +// OnDestroy mocks base method. +func (m *MockNetworkFilter) OnDestroy() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OnDestroy") +} + +// OnDestroy indicates an expected call of OnDestroy. +func (mr *MockNetworkFilterMockRecorder) OnDestroy() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnDestroy", reflect.TypeOf((*MockNetworkFilter)(nil).OnDestroy)) +} + +// OnEvent mocks base method. +func (m *MockNetworkFilter) OnEvent(event shared.NetworkConnectionEvent) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OnEvent", event) +} + +// OnEvent indicates an expected call of OnEvent. +func (mr *MockNetworkFilterMockRecorder) OnEvent(event any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnEvent", reflect.TypeOf((*MockNetworkFilter)(nil).OnEvent), event) +} + +// OnNewConnection mocks base method. +func (m *MockNetworkFilter) OnNewConnection() shared.NetworkFilterStatus { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnNewConnection") + ret0, _ := ret[0].(shared.NetworkFilterStatus) + return ret0 +} + +// OnNewConnection indicates an expected call of OnNewConnection. +func (mr *MockNetworkFilterMockRecorder) OnNewConnection() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnNewConnection", reflect.TypeOf((*MockNetworkFilter)(nil).OnNewConnection)) +} + +// OnRead mocks base method. +func (m *MockNetworkFilter) OnRead(data shared.NetworkBuffer, endOfStream bool) shared.NetworkFilterStatus { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnRead", data, endOfStream) + ret0, _ := ret[0].(shared.NetworkFilterStatus) + return ret0 +} + +// OnRead indicates an expected call of OnRead. +func (mr *MockNetworkFilterMockRecorder) OnRead(data, endOfStream any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnRead", reflect.TypeOf((*MockNetworkFilter)(nil).OnRead), data, endOfStream) +} + +// OnWrite mocks base method. +func (m *MockNetworkFilter) OnWrite(data shared.NetworkBuffer, endOfStream bool) shared.NetworkFilterStatus { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnWrite", data, endOfStream) + ret0, _ := ret[0].(shared.NetworkFilterStatus) + return ret0 +} + +// OnWrite indicates an expected call of OnWrite. +func (mr *MockNetworkFilterMockRecorder) OnWrite(data, endOfStream any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnWrite", reflect.TypeOf((*MockNetworkFilter)(nil).OnWrite), data, endOfStream) +} + +// MockNetworkFilterFactory is a mock of NetworkFilterFactory interface. +type MockNetworkFilterFactory struct { + ctrl *gomock.Controller + recorder *MockNetworkFilterFactoryMockRecorder + isgomock struct{} +} + +// MockNetworkFilterFactoryMockRecorder is the mock recorder for MockNetworkFilterFactory. +type MockNetworkFilterFactoryMockRecorder struct { + mock *MockNetworkFilterFactory +} + +// NewMockNetworkFilterFactory creates a new mock instance. +func NewMockNetworkFilterFactory(ctrl *gomock.Controller) *MockNetworkFilterFactory { + mock := &MockNetworkFilterFactory{ctrl: ctrl} + mock.recorder = &MockNetworkFilterFactoryMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockNetworkFilterFactory) EXPECT() *MockNetworkFilterFactoryMockRecorder { + return m.recorder +} + +// Create mocks base method. +func (m *MockNetworkFilterFactory) Create(handle shared.NetworkFilterHandle) shared.NetworkFilter { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Create", handle) + ret0, _ := ret[0].(shared.NetworkFilter) + return ret0 +} + +// Create indicates an expected call of Create. +func (mr *MockNetworkFilterFactoryMockRecorder) Create(handle any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockNetworkFilterFactory)(nil).Create), handle) +} + +// OnDestroy mocks base method. +func (m *MockNetworkFilterFactory) OnDestroy() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OnDestroy") +} + +// OnDestroy indicates an expected call of OnDestroy. +func (mr *MockNetworkFilterFactoryMockRecorder) OnDestroy() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnDestroy", reflect.TypeOf((*MockNetworkFilterFactory)(nil).OnDestroy)) +} + +// MockNetworkFilterConfigFactory is a mock of NetworkFilterConfigFactory interface. +type MockNetworkFilterConfigFactory struct { + ctrl *gomock.Controller + recorder *MockNetworkFilterConfigFactoryMockRecorder + isgomock struct{} +} + +// MockNetworkFilterConfigFactoryMockRecorder is the mock recorder for MockNetworkFilterConfigFactory. +type MockNetworkFilterConfigFactoryMockRecorder struct { + mock *MockNetworkFilterConfigFactory +} + +// NewMockNetworkFilterConfigFactory creates a new mock instance. +func NewMockNetworkFilterConfigFactory(ctrl *gomock.Controller) *MockNetworkFilterConfigFactory { + mock := &MockNetworkFilterConfigFactory{ctrl: ctrl} + mock.recorder = &MockNetworkFilterConfigFactoryMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockNetworkFilterConfigFactory) EXPECT() *MockNetworkFilterConfigFactoryMockRecorder { + return m.recorder +} + +// Create mocks base method. +func (m *MockNetworkFilterConfigFactory) Create(handle shared.NetworkFilterConfigHandle, unparsedConfig []byte) (shared.NetworkFilterFactory, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Create", handle, unparsedConfig) + ret0, _ := ret[0].(shared.NetworkFilterFactory) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Create indicates an expected call of Create. +func (mr *MockNetworkFilterConfigFactoryMockRecorder) Create(handle, unparsedConfig any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockNetworkFilterConfigFactory)(nil).Create), handle, unparsedConfig) +} diff --git a/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_network_base.go b/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_network_base.go new file mode 100644 index 0000000000000..b42fd2634b665 --- /dev/null +++ b/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_network_base.go @@ -0,0 +1,991 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: network_base.go +// +// Generated by this command: +// +// mockgen -source=network_base.go -destination=mocks/mock_network_base.go -package=mocks +// + +// Package mocks is a generated GoMock package. +package mocks + +import ( + reflect "reflect" + + shared "github.com/envoyproxy/envoy/source/extensions/dynamic_modules/sdk/go/shared" + gomock "go.uber.org/mock/gomock" +) + +// MockNetworkBuffer is a mock of NetworkBuffer interface. +type MockNetworkBuffer struct { + ctrl *gomock.Controller + recorder *MockNetworkBufferMockRecorder + isgomock struct{} +} + +// MockNetworkBufferMockRecorder is the mock recorder for MockNetworkBuffer. +type MockNetworkBufferMockRecorder struct { + mock *MockNetworkBuffer +} + +// NewMockNetworkBuffer creates a new mock instance. +func NewMockNetworkBuffer(ctrl *gomock.Controller) *MockNetworkBuffer { + mock := &MockNetworkBuffer{ctrl: ctrl} + mock.recorder = &MockNetworkBufferMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockNetworkBuffer) EXPECT() *MockNetworkBufferMockRecorder { + return m.recorder +} + +// Append mocks base method. +func (m *MockNetworkBuffer) Append(data []byte) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Append", data) + ret0, _ := ret[0].(bool) + return ret0 +} + +// Append indicates an expected call of Append. +func (mr *MockNetworkBufferMockRecorder) Append(data any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Append", reflect.TypeOf((*MockNetworkBuffer)(nil).Append), data) +} + +// Drain mocks base method. +func (m *MockNetworkBuffer) Drain(numBytes uint64) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Drain", numBytes) + ret0, _ := ret[0].(bool) + return ret0 +} + +// Drain indicates an expected call of Drain. +func (mr *MockNetworkBufferMockRecorder) Drain(numBytes any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Drain", reflect.TypeOf((*MockNetworkBuffer)(nil).Drain), numBytes) +} + +// GetChunks mocks base method. +func (m *MockNetworkBuffer) GetChunks() []shared.UnsafeEnvoyBuffer { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetChunks") + ret0, _ := ret[0].([]shared.UnsafeEnvoyBuffer) + return ret0 +} + +// GetChunks indicates an expected call of GetChunks. +func (mr *MockNetworkBufferMockRecorder) GetChunks() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetChunks", reflect.TypeOf((*MockNetworkBuffer)(nil).GetChunks)) +} + +// GetSize mocks base method. +func (m *MockNetworkBuffer) GetSize() uint64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSize") + ret0, _ := ret[0].(uint64) + return ret0 +} + +// GetSize indicates an expected call of GetSize. +func (mr *MockNetworkBufferMockRecorder) GetSize() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSize", reflect.TypeOf((*MockNetworkBuffer)(nil).GetSize)) +} + +// Prepend mocks base method. +func (m *MockNetworkBuffer) Prepend(data []byte) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Prepend", data) + ret0, _ := ret[0].(bool) + return ret0 +} + +// Prepend indicates an expected call of Prepend. +func (mr *MockNetworkBufferMockRecorder) Prepend(data any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Prepend", reflect.TypeOf((*MockNetworkBuffer)(nil).Prepend), data) +} + +// MockNetworkFilterHandle is a mock of NetworkFilterHandle interface. +type MockNetworkFilterHandle struct { + ctrl *gomock.Controller + recorder *MockNetworkFilterHandleMockRecorder + isgomock struct{} +} + +// MockNetworkFilterHandleMockRecorder is the mock recorder for MockNetworkFilterHandle. +type MockNetworkFilterHandleMockRecorder struct { + mock *MockNetworkFilterHandle +} + +// NewMockNetworkFilterHandle creates a new mock instance. +func NewMockNetworkFilterHandle(ctrl *gomock.Controller) *MockNetworkFilterHandle { + mock := &MockNetworkFilterHandle{ctrl: ctrl} + mock.recorder = &MockNetworkFilterHandleMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockNetworkFilterHandle) EXPECT() *MockNetworkFilterHandleMockRecorder { + return m.recorder +} + +// AboveHighWatermark mocks base method. +func (m *MockNetworkFilterHandle) AboveHighWatermark() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AboveHighWatermark") + ret0, _ := ret[0].(bool) + return ret0 +} + +// AboveHighWatermark indicates an expected call of AboveHighWatermark. +func (mr *MockNetworkFilterHandleMockRecorder) AboveHighWatermark() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AboveHighWatermark", reflect.TypeOf((*MockNetworkFilterHandle)(nil).AboveHighWatermark)) +} + +// Close mocks base method. +func (m *MockNetworkFilterHandle) Close(closeType shared.NetworkConnectionCloseType) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Close", closeType) +} + +// Close indicates an expected call of Close. +func (mr *MockNetworkFilterHandleMockRecorder) Close(closeType any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockNetworkFilterHandle)(nil).Close), closeType) +} + +// CloseWithDetails mocks base method. +func (m *MockNetworkFilterHandle) CloseWithDetails(closeType shared.NetworkConnectionCloseType, details string) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "CloseWithDetails", closeType, details) +} + +// CloseWithDetails indicates an expected call of CloseWithDetails. +func (mr *MockNetworkFilterHandleMockRecorder) CloseWithDetails(closeType, details any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CloseWithDetails", reflect.TypeOf((*MockNetworkFilterHandle)(nil).CloseWithDetails), closeType, details) +} + +// ContinueReading mocks base method. +func (m *MockNetworkFilterHandle) ContinueReading() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "ContinueReading") +} + +// ContinueReading indicates an expected call of ContinueReading. +func (mr *MockNetworkFilterHandleMockRecorder) ContinueReading() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ContinueReading", reflect.TypeOf((*MockNetworkFilterHandle)(nil).ContinueReading)) +} + +// DecrementGaugeValue mocks base method. +func (m *MockNetworkFilterHandle) DecrementGaugeValue(id shared.MetricID, value uint64) shared.MetricsResult { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DecrementGaugeValue", id, value) + ret0, _ := ret[0].(shared.MetricsResult) + return ret0 +} + +// DecrementGaugeValue indicates an expected call of DecrementGaugeValue. +func (mr *MockNetworkFilterHandleMockRecorder) DecrementGaugeValue(id, value any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DecrementGaugeValue", reflect.TypeOf((*MockNetworkFilterHandle)(nil).DecrementGaugeValue), id, value) +} + +// DisableClose mocks base method. +func (m *MockNetworkFilterHandle) DisableClose(disabled bool) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "DisableClose", disabled) +} + +// DisableClose indicates an expected call of DisableClose. +func (mr *MockNetworkFilterHandleMockRecorder) DisableClose(disabled any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DisableClose", reflect.TypeOf((*MockNetworkFilterHandle)(nil).DisableClose), disabled) +} + +// EnableHalfClose mocks base method. +func (m *MockNetworkFilterHandle) EnableHalfClose(enabled bool) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "EnableHalfClose", enabled) +} + +// EnableHalfClose indicates an expected call of EnableHalfClose. +func (mr *MockNetworkFilterHandleMockRecorder) EnableHalfClose(enabled any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EnableHalfClose", reflect.TypeOf((*MockNetworkFilterHandle)(nil).EnableHalfClose), enabled) +} + +// GetBufferLimit mocks base method. +func (m *MockNetworkFilterHandle) GetBufferLimit() uint32 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetBufferLimit") + ret0, _ := ret[0].(uint32) + return ret0 +} + +// GetBufferLimit indicates an expected call of GetBufferLimit. +func (mr *MockNetworkFilterHandleMockRecorder) GetBufferLimit() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBufferLimit", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetBufferLimit)) +} + +// GetClusterHostCounts mocks base method. +func (m *MockNetworkFilterHandle) GetClusterHostCounts(cluster string, priority uint32) (shared.ClusterHostCounts, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetClusterHostCounts", cluster, priority) + ret0, _ := ret[0].(shared.ClusterHostCounts) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// GetClusterHostCounts indicates an expected call of GetClusterHostCounts. +func (mr *MockNetworkFilterHandleMockRecorder) GetClusterHostCounts(cluster, priority any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetClusterHostCounts", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetClusterHostCounts), cluster, priority) +} + +// GetConnectionID mocks base method. +func (m *MockNetworkFilterHandle) GetConnectionID() uint64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetConnectionID") + ret0, _ := ret[0].(uint64) + return ret0 +} + +// GetConnectionID indicates an expected call of GetConnectionID. +func (mr *MockNetworkFilterHandleMockRecorder) GetConnectionID() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetConnectionID", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetConnectionID)) +} + +// GetConnectionState mocks base method. +func (m *MockNetworkFilterHandle) GetConnectionState() shared.NetworkConnectionState { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetConnectionState") + ret0, _ := ret[0].(shared.NetworkConnectionState) + return ret0 +} + +// GetConnectionState indicates an expected call of GetConnectionState. +func (mr *MockNetworkFilterHandleMockRecorder) GetConnectionState() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetConnectionState", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetConnectionState)) +} + +// GetDirectRemoteAddress mocks base method. +func (m *MockNetworkFilterHandle) GetDirectRemoteAddress() (shared.UnsafeEnvoyBuffer, uint32, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetDirectRemoteAddress") + ret0, _ := ret[0].(shared.UnsafeEnvoyBuffer) + ret1, _ := ret[1].(uint32) + ret2, _ := ret[2].(bool) + return ret0, ret1, ret2 +} + +// GetDirectRemoteAddress indicates an expected call of GetDirectRemoteAddress. +func (mr *MockNetworkFilterHandleMockRecorder) GetDirectRemoteAddress() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDirectRemoteAddress", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetDirectRemoteAddress)) +} + +// GetFilterState mocks base method. +func (m *MockNetworkFilterHandle) GetFilterState(key string) (shared.UnsafeEnvoyBuffer, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetFilterState", key) + ret0, _ := ret[0].(shared.UnsafeEnvoyBuffer) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// GetFilterState indicates an expected call of GetFilterState. +func (mr *MockNetworkFilterHandleMockRecorder) GetFilterState(key any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFilterState", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetFilterState), key) +} + +// GetFilterStateTyped mocks base method. +func (m *MockNetworkFilterHandle) GetFilterStateTyped(key string) (shared.UnsafeEnvoyBuffer, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetFilterStateTyped", key) + ret0, _ := ret[0].(shared.UnsafeEnvoyBuffer) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// GetFilterStateTyped indicates an expected call of GetFilterStateTyped. +func (mr *MockNetworkFilterHandleMockRecorder) GetFilterStateTyped(key any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFilterStateTyped", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetFilterStateTyped), key) +} + +// GetLocalAddress mocks base method. +func (m *MockNetworkFilterHandle) GetLocalAddress() (shared.UnsafeEnvoyBuffer, uint32, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetLocalAddress") + ret0, _ := ret[0].(shared.UnsafeEnvoyBuffer) + ret1, _ := ret[1].(uint32) + ret2, _ := ret[2].(bool) + return ret0, ret1, ret2 +} + +// GetLocalAddress indicates an expected call of GetLocalAddress. +func (mr *MockNetworkFilterHandleMockRecorder) GetLocalAddress() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLocalAddress", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetLocalAddress)) +} + +// GetMetadataBool mocks base method. +func (m *MockNetworkFilterHandle) GetMetadataBool(metadataNamespace, key string) (bool, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetMetadataBool", metadataNamespace, key) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// GetMetadataBool indicates an expected call of GetMetadataBool. +func (mr *MockNetworkFilterHandleMockRecorder) GetMetadataBool(metadataNamespace, key any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMetadataBool", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetMetadataBool), metadataNamespace, key) +} + +// GetMetadataNumber mocks base method. +func (m *MockNetworkFilterHandle) GetMetadataNumber(metadataNamespace, key string) (float64, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetMetadataNumber", metadataNamespace, key) + ret0, _ := ret[0].(float64) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// GetMetadataNumber indicates an expected call of GetMetadataNumber. +func (mr *MockNetworkFilterHandleMockRecorder) GetMetadataNumber(metadataNamespace, key any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMetadataNumber", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetMetadataNumber), metadataNamespace, key) +} + +// GetMetadataString mocks base method. +func (m *MockNetworkFilterHandle) GetMetadataString(metadataNamespace, key string) (shared.UnsafeEnvoyBuffer, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetMetadataString", metadataNamespace, key) + ret0, _ := ret[0].(shared.UnsafeEnvoyBuffer) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// GetMetadataString indicates an expected call of GetMetadataString. +func (mr *MockNetworkFilterHandleMockRecorder) GetMetadataString(metadataNamespace, key any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMetadataString", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetMetadataString), metadataNamespace, key) +} + +// GetRemoteAddress mocks base method. +func (m *MockNetworkFilterHandle) GetRemoteAddress() (shared.UnsafeEnvoyBuffer, uint32, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetRemoteAddress") + ret0, _ := ret[0].(shared.UnsafeEnvoyBuffer) + ret1, _ := ret[1].(uint32) + ret2, _ := ret[2].(bool) + return ret0, ret1, ret2 +} + +// GetRemoteAddress indicates an expected call of GetRemoteAddress. +func (mr *MockNetworkFilterHandleMockRecorder) GetRemoteAddress() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRemoteAddress", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetRemoteAddress)) +} + +// GetRequestedServerName mocks base method. +func (m *MockNetworkFilterHandle) GetRequestedServerName() (shared.UnsafeEnvoyBuffer, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetRequestedServerName") + ret0, _ := ret[0].(shared.UnsafeEnvoyBuffer) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// GetRequestedServerName indicates an expected call of GetRequestedServerName. +func (mr *MockNetworkFilterHandleMockRecorder) GetRequestedServerName() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRequestedServerName", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetRequestedServerName)) +} + +// GetSSLDNSSANs mocks base method. +func (m *MockNetworkFilterHandle) GetSSLDNSSANs() []shared.UnsafeEnvoyBuffer { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSSLDNSSANs") + ret0, _ := ret[0].([]shared.UnsafeEnvoyBuffer) + return ret0 +} + +// GetSSLDNSSANs indicates an expected call of GetSSLDNSSANs. +func (mr *MockNetworkFilterHandleMockRecorder) GetSSLDNSSANs() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSSLDNSSANs", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetSSLDNSSANs)) +} + +// GetSSLSubject mocks base method. +func (m *MockNetworkFilterHandle) GetSSLSubject() (shared.UnsafeEnvoyBuffer, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSSLSubject") + ret0, _ := ret[0].(shared.UnsafeEnvoyBuffer) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// GetSSLSubject indicates an expected call of GetSSLSubject. +func (mr *MockNetworkFilterHandleMockRecorder) GetSSLSubject() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSSLSubject", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetSSLSubject)) +} + +// GetSSLURISANs mocks base method. +func (m *MockNetworkFilterHandle) GetSSLURISANs() []shared.UnsafeEnvoyBuffer { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSSLURISANs") + ret0, _ := ret[0].([]shared.UnsafeEnvoyBuffer) + return ret0 +} + +// GetSSLURISANs indicates an expected call of GetSSLURISANs. +func (mr *MockNetworkFilterHandleMockRecorder) GetSSLURISANs() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSSLURISANs", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetSSLURISANs)) +} + +// GetScheduler mocks base method. +func (m *MockNetworkFilterHandle) GetScheduler() shared.Scheduler { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetScheduler") + ret0, _ := ret[0].(shared.Scheduler) + return ret0 +} + +// GetScheduler indicates an expected call of GetScheduler. +func (mr *MockNetworkFilterHandleMockRecorder) GetScheduler() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetScheduler", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetScheduler)) +} + +// GetSocketOptionBytes mocks base method. +func (m *MockNetworkFilterHandle) GetSocketOptionBytes(level, name int64, state shared.SocketOptionState) (shared.UnsafeEnvoyBuffer, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSocketOptionBytes", level, name, state) + ret0, _ := ret[0].(shared.UnsafeEnvoyBuffer) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// GetSocketOptionBytes indicates an expected call of GetSocketOptionBytes. +func (mr *MockNetworkFilterHandleMockRecorder) GetSocketOptionBytes(level, name, state any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSocketOptionBytes", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetSocketOptionBytes), level, name, state) +} + +// GetSocketOptionInt mocks base method. +func (m *MockNetworkFilterHandle) GetSocketOptionInt(level, name int64, state shared.SocketOptionState) (int64, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSocketOptionInt", level, name, state) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// GetSocketOptionInt indicates an expected call of GetSocketOptionInt. +func (mr *MockNetworkFilterHandleMockRecorder) GetSocketOptionInt(level, name, state any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSocketOptionInt", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetSocketOptionInt), level, name, state) +} + +// GetSocketOptions mocks base method. +func (m *MockNetworkFilterHandle) GetSocketOptions() []shared.SocketOption { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSocketOptions") + ret0, _ := ret[0].([]shared.SocketOption) + return ret0 +} + +// GetSocketOptions indicates an expected call of GetSocketOptions. +func (mr *MockNetworkFilterHandleMockRecorder) GetSocketOptions() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSocketOptions", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetSocketOptions)) +} + +// GetUpstreamHostAddress mocks base method. +func (m *MockNetworkFilterHandle) GetUpstreamHostAddress() (shared.UnsafeEnvoyBuffer, uint32, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUpstreamHostAddress") + ret0, _ := ret[0].(shared.UnsafeEnvoyBuffer) + ret1, _ := ret[1].(uint32) + ret2, _ := ret[2].(bool) + return ret0, ret1, ret2 +} + +// GetUpstreamHostAddress indicates an expected call of GetUpstreamHostAddress. +func (mr *MockNetworkFilterHandleMockRecorder) GetUpstreamHostAddress() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUpstreamHostAddress", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetUpstreamHostAddress)) +} + +// GetUpstreamHostCluster mocks base method. +func (m *MockNetworkFilterHandle) GetUpstreamHostCluster() (shared.UnsafeEnvoyBuffer, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUpstreamHostCluster") + ret0, _ := ret[0].(shared.UnsafeEnvoyBuffer) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// GetUpstreamHostCluster indicates an expected call of GetUpstreamHostCluster. +func (mr *MockNetworkFilterHandleMockRecorder) GetUpstreamHostCluster() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUpstreamHostCluster", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetUpstreamHostCluster)) +} + +// GetUpstreamHostHostname mocks base method. +func (m *MockNetworkFilterHandle) GetUpstreamHostHostname() (shared.UnsafeEnvoyBuffer, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUpstreamHostHostname") + ret0, _ := ret[0].(shared.UnsafeEnvoyBuffer) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// GetUpstreamHostHostname indicates an expected call of GetUpstreamHostHostname. +func (mr *MockNetworkFilterHandleMockRecorder) GetUpstreamHostHostname() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUpstreamHostHostname", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetUpstreamHostHostname)) +} + +// GetWorkerIndex mocks base method. +func (m *MockNetworkFilterHandle) GetWorkerIndex() uint32 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkerIndex") + ret0, _ := ret[0].(uint32) + return ret0 +} + +// GetWorkerIndex indicates an expected call of GetWorkerIndex. +func (mr *MockNetworkFilterHandleMockRecorder) GetWorkerIndex() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkerIndex", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetWorkerIndex)) +} + +// HasUpstreamHost mocks base method. +func (m *MockNetworkFilterHandle) HasUpstreamHost() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HasUpstreamHost") + ret0, _ := ret[0].(bool) + return ret0 +} + +// HasUpstreamHost indicates an expected call of HasUpstreamHost. +func (mr *MockNetworkFilterHandleMockRecorder) HasUpstreamHost() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasUpstreamHost", reflect.TypeOf((*MockNetworkFilterHandle)(nil).HasUpstreamHost)) +} + +// HttpCallout mocks base method. +func (m *MockNetworkFilterHandle) HttpCallout(cluster string, headers [][2]string, body []byte, timeoutMs uint64, cb shared.HttpCalloutCallback) (shared.HttpCalloutInitResult, uint64) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HttpCallout", cluster, headers, body, timeoutMs, cb) + ret0, _ := ret[0].(shared.HttpCalloutInitResult) + ret1, _ := ret[1].(uint64) + return ret0, ret1 +} + +// HttpCallout indicates an expected call of HttpCallout. +func (mr *MockNetworkFilterHandleMockRecorder) HttpCallout(cluster, headers, body, timeoutMs, cb any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HttpCallout", reflect.TypeOf((*MockNetworkFilterHandle)(nil).HttpCallout), cluster, headers, body, timeoutMs, cb) +} + +// IncrementCounterValue mocks base method. +func (m *MockNetworkFilterHandle) IncrementCounterValue(id shared.MetricID, value uint64) shared.MetricsResult { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IncrementCounterValue", id, value) + ret0, _ := ret[0].(shared.MetricsResult) + return ret0 +} + +// IncrementCounterValue indicates an expected call of IncrementCounterValue. +func (mr *MockNetworkFilterHandleMockRecorder) IncrementCounterValue(id, value any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IncrementCounterValue", reflect.TypeOf((*MockNetworkFilterHandle)(nil).IncrementCounterValue), id, value) +} + +// IncrementGaugeValue mocks base method. +func (m *MockNetworkFilterHandle) IncrementGaugeValue(id shared.MetricID, value uint64) shared.MetricsResult { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IncrementGaugeValue", id, value) + ret0, _ := ret[0].(shared.MetricsResult) + return ret0 +} + +// IncrementGaugeValue indicates an expected call of IncrementGaugeValue. +func (mr *MockNetworkFilterHandleMockRecorder) IncrementGaugeValue(id, value any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IncrementGaugeValue", reflect.TypeOf((*MockNetworkFilterHandle)(nil).IncrementGaugeValue), id, value) +} + +// InjectReadData mocks base method. +func (m *MockNetworkFilterHandle) InjectReadData(data []byte, endStream bool) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "InjectReadData", data, endStream) +} + +// InjectReadData indicates an expected call of InjectReadData. +func (mr *MockNetworkFilterHandleMockRecorder) InjectReadData(data, endStream any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InjectReadData", reflect.TypeOf((*MockNetworkFilterHandle)(nil).InjectReadData), data, endStream) +} + +// InjectWriteData mocks base method. +func (m *MockNetworkFilterHandle) InjectWriteData(data []byte, endStream bool) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "InjectWriteData", data, endStream) +} + +// InjectWriteData indicates an expected call of InjectWriteData. +func (mr *MockNetworkFilterHandleMockRecorder) InjectWriteData(data, endStream any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InjectWriteData", reflect.TypeOf((*MockNetworkFilterHandle)(nil).InjectWriteData), data, endStream) +} + +// IsHalfCloseEnabled mocks base method. +func (m *MockNetworkFilterHandle) IsHalfCloseEnabled() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsHalfCloseEnabled") + ret0, _ := ret[0].(bool) + return ret0 +} + +// IsHalfCloseEnabled indicates an expected call of IsHalfCloseEnabled. +func (mr *MockNetworkFilterHandleMockRecorder) IsHalfCloseEnabled() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsHalfCloseEnabled", reflect.TypeOf((*MockNetworkFilterHandle)(nil).IsHalfCloseEnabled)) +} + +// IsSSL mocks base method. +func (m *MockNetworkFilterHandle) IsSSL() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsSSL") + ret0, _ := ret[0].(bool) + return ret0 +} + +// IsSSL indicates an expected call of IsSSL. +func (mr *MockNetworkFilterHandleMockRecorder) IsSSL() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsSSL", reflect.TypeOf((*MockNetworkFilterHandle)(nil).IsSSL)) +} + +// Log mocks base method. +func (m *MockNetworkFilterHandle) Log(level shared.LogLevel, format string, args ...any) { + m.ctrl.T.Helper() + varargs := []any{level, format} + for _, a := range args { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "Log", varargs...) +} + +// Log indicates an expected call of Log. +func (mr *MockNetworkFilterHandleMockRecorder) Log(level, format any, args ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{level, format}, args...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Log", reflect.TypeOf((*MockNetworkFilterHandle)(nil).Log), varargs...) +} + +// ReadBuffer mocks base method. +func (m *MockNetworkFilterHandle) ReadBuffer() shared.NetworkBuffer { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ReadBuffer") + ret0, _ := ret[0].(shared.NetworkBuffer) + return ret0 +} + +// ReadBuffer indicates an expected call of ReadBuffer. +func (mr *MockNetworkFilterHandleMockRecorder) ReadBuffer() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadBuffer", reflect.TypeOf((*MockNetworkFilterHandle)(nil).ReadBuffer)) +} + +// ReadDisable mocks base method. +func (m *MockNetworkFilterHandle) ReadDisable(disable bool) shared.NetworkReadDisableStatus { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ReadDisable", disable) + ret0, _ := ret[0].(shared.NetworkReadDisableStatus) + return ret0 +} + +// ReadDisable indicates an expected call of ReadDisable. +func (mr *MockNetworkFilterHandleMockRecorder) ReadDisable(disable any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadDisable", reflect.TypeOf((*MockNetworkFilterHandle)(nil).ReadDisable), disable) +} + +// ReadEnabled mocks base method. +func (m *MockNetworkFilterHandle) ReadEnabled() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ReadEnabled") + ret0, _ := ret[0].(bool) + return ret0 +} + +// ReadEnabled indicates an expected call of ReadEnabled. +func (mr *MockNetworkFilterHandleMockRecorder) ReadEnabled() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadEnabled", reflect.TypeOf((*MockNetworkFilterHandle)(nil).ReadEnabled)) +} + +// RecordHistogramValue mocks base method. +func (m *MockNetworkFilterHandle) RecordHistogramValue(id shared.MetricID, value uint64) shared.MetricsResult { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RecordHistogramValue", id, value) + ret0, _ := ret[0].(shared.MetricsResult) + return ret0 +} + +// RecordHistogramValue indicates an expected call of RecordHistogramValue. +func (mr *MockNetworkFilterHandleMockRecorder) RecordHistogramValue(id, value any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordHistogramValue", reflect.TypeOf((*MockNetworkFilterHandle)(nil).RecordHistogramValue), id, value) +} + +// SetBufferLimits mocks base method. +func (m *MockNetworkFilterHandle) SetBufferLimits(limit uint32) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetBufferLimits", limit) +} + +// SetBufferLimits indicates an expected call of SetBufferLimits. +func (mr *MockNetworkFilterHandleMockRecorder) SetBufferLimits(limit any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetBufferLimits", reflect.TypeOf((*MockNetworkFilterHandle)(nil).SetBufferLimits), limit) +} + +// SetFilterState mocks base method. +func (m *MockNetworkFilterHandle) SetFilterState(key string, value []byte) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetFilterState", key, value) + ret0, _ := ret[0].(bool) + return ret0 +} + +// SetFilterState indicates an expected call of SetFilterState. +func (mr *MockNetworkFilterHandleMockRecorder) SetFilterState(key, value any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFilterState", reflect.TypeOf((*MockNetworkFilterHandle)(nil).SetFilterState), key, value) +} + +// SetFilterStateTyped mocks base method. +func (m *MockNetworkFilterHandle) SetFilterStateTyped(key string, value []byte) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetFilterStateTyped", key, value) + ret0, _ := ret[0].(bool) + return ret0 +} + +// SetFilterStateTyped indicates an expected call of SetFilterStateTyped. +func (mr *MockNetworkFilterHandleMockRecorder) SetFilterStateTyped(key, value any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFilterStateTyped", reflect.TypeOf((*MockNetworkFilterHandle)(nil).SetFilterStateTyped), key, value) +} + +// SetGaugeValue mocks base method. +func (m *MockNetworkFilterHandle) SetGaugeValue(id shared.MetricID, value uint64) shared.MetricsResult { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetGaugeValue", id, value) + ret0, _ := ret[0].(shared.MetricsResult) + return ret0 +} + +// SetGaugeValue indicates an expected call of SetGaugeValue. +func (mr *MockNetworkFilterHandleMockRecorder) SetGaugeValue(id, value any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetGaugeValue", reflect.TypeOf((*MockNetworkFilterHandle)(nil).SetGaugeValue), id, value) +} + +// SetMetadata mocks base method. +func (m *MockNetworkFilterHandle) SetMetadata(metadataNamespace, key string, value any) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetMetadata", metadataNamespace, key, value) +} + +// SetMetadata indicates an expected call of SetMetadata. +func (mr *MockNetworkFilterHandleMockRecorder) SetMetadata(metadataNamespace, key, value any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetMetadata", reflect.TypeOf((*MockNetworkFilterHandle)(nil).SetMetadata), metadataNamespace, key, value) +} + +// SetSocketOptionBytes mocks base method. +func (m *MockNetworkFilterHandle) SetSocketOptionBytes(level, name int64, state shared.SocketOptionState, value []byte) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetSocketOptionBytes", level, name, state, value) +} + +// SetSocketOptionBytes indicates an expected call of SetSocketOptionBytes. +func (mr *MockNetworkFilterHandleMockRecorder) SetSocketOptionBytes(level, name, state, value any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSocketOptionBytes", reflect.TypeOf((*MockNetworkFilterHandle)(nil).SetSocketOptionBytes), level, name, state, value) +} + +// SetSocketOptionInt mocks base method. +func (m *MockNetworkFilterHandle) SetSocketOptionInt(level, name int64, state shared.SocketOptionState, value int64) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetSocketOptionInt", level, name, state, value) +} + +// SetSocketOptionInt indicates an expected call of SetSocketOptionInt. +func (mr *MockNetworkFilterHandleMockRecorder) SetSocketOptionInt(level, name, state, value any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSocketOptionInt", reflect.TypeOf((*MockNetworkFilterHandle)(nil).SetSocketOptionInt), level, name, state, value) +} + +// StartUpstreamSecureTransport mocks base method. +func (m *MockNetworkFilterHandle) StartUpstreamSecureTransport() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StartUpstreamSecureTransport") + ret0, _ := ret[0].(bool) + return ret0 +} + +// StartUpstreamSecureTransport indicates an expected call of StartUpstreamSecureTransport. +func (mr *MockNetworkFilterHandleMockRecorder) StartUpstreamSecureTransport() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartUpstreamSecureTransport", reflect.TypeOf((*MockNetworkFilterHandle)(nil).StartUpstreamSecureTransport)) +} + +// Write mocks base method. +func (m *MockNetworkFilterHandle) Write(data []byte, endStream bool) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Write", data, endStream) +} + +// Write indicates an expected call of Write. +func (mr *MockNetworkFilterHandleMockRecorder) Write(data, endStream any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Write", reflect.TypeOf((*MockNetworkFilterHandle)(nil).Write), data, endStream) +} + +// WriteBuffer mocks base method. +func (m *MockNetworkFilterHandle) WriteBuffer() shared.NetworkBuffer { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "WriteBuffer") + ret0, _ := ret[0].(shared.NetworkBuffer) + return ret0 +} + +// WriteBuffer indicates an expected call of WriteBuffer. +func (mr *MockNetworkFilterHandleMockRecorder) WriteBuffer() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WriteBuffer", reflect.TypeOf((*MockNetworkFilterHandle)(nil).WriteBuffer)) +} + +// MockNetworkFilterConfigHandle is a mock of NetworkFilterConfigHandle interface. +type MockNetworkFilterConfigHandle struct { + ctrl *gomock.Controller + recorder *MockNetworkFilterConfigHandleMockRecorder + isgomock struct{} +} + +// MockNetworkFilterConfigHandleMockRecorder is the mock recorder for MockNetworkFilterConfigHandle. +type MockNetworkFilterConfigHandleMockRecorder struct { + mock *MockNetworkFilterConfigHandle +} + +// NewMockNetworkFilterConfigHandle creates a new mock instance. +func NewMockNetworkFilterConfigHandle(ctrl *gomock.Controller) *MockNetworkFilterConfigHandle { + mock := &MockNetworkFilterConfigHandle{ctrl: ctrl} + mock.recorder = &MockNetworkFilterConfigHandleMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockNetworkFilterConfigHandle) EXPECT() *MockNetworkFilterConfigHandleMockRecorder { + return m.recorder +} + +// DefineCounter mocks base method. +func (m *MockNetworkFilterConfigHandle) DefineCounter(name string) (shared.MetricID, shared.MetricsResult) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefineCounter", name) + ret0, _ := ret[0].(shared.MetricID) + ret1, _ := ret[1].(shared.MetricsResult) + return ret0, ret1 +} + +// DefineCounter indicates an expected call of DefineCounter. +func (mr *MockNetworkFilterConfigHandleMockRecorder) DefineCounter(name any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefineCounter", reflect.TypeOf((*MockNetworkFilterConfigHandle)(nil).DefineCounter), name) +} + +// DefineGauge mocks base method. +func (m *MockNetworkFilterConfigHandle) DefineGauge(name string) (shared.MetricID, shared.MetricsResult) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefineGauge", name) + ret0, _ := ret[0].(shared.MetricID) + ret1, _ := ret[1].(shared.MetricsResult) + return ret0, ret1 +} + +// DefineGauge indicates an expected call of DefineGauge. +func (mr *MockNetworkFilterConfigHandleMockRecorder) DefineGauge(name any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefineGauge", reflect.TypeOf((*MockNetworkFilterConfigHandle)(nil).DefineGauge), name) +} + +// DefineHistogram mocks base method. +func (m *MockNetworkFilterConfigHandle) DefineHistogram(name string) (shared.MetricID, shared.MetricsResult) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefineHistogram", name) + ret0, _ := ret[0].(shared.MetricID) + ret1, _ := ret[1].(shared.MetricsResult) + return ret0, ret1 +} + +// DefineHistogram indicates an expected call of DefineHistogram. +func (mr *MockNetworkFilterConfigHandleMockRecorder) DefineHistogram(name any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefineHistogram", reflect.TypeOf((*MockNetworkFilterConfigHandle)(nil).DefineHistogram), name) +} + +// GetScheduler mocks base method. +func (m *MockNetworkFilterConfigHandle) GetScheduler() shared.Scheduler { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetScheduler") + ret0, _ := ret[0].(shared.Scheduler) + return ret0 +} + +// GetScheduler indicates an expected call of GetScheduler. +func (mr *MockNetworkFilterConfigHandleMockRecorder) GetScheduler() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetScheduler", reflect.TypeOf((*MockNetworkFilterConfigHandle)(nil).GetScheduler)) +} + +// Log mocks base method. +func (m *MockNetworkFilterConfigHandle) Log(level shared.LogLevel, format string, args ...any) { + m.ctrl.T.Helper() + varargs := []any{level, format} + for _, a := range args { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "Log", varargs...) +} + +// Log indicates an expected call of Log. +func (mr *MockNetworkFilterConfigHandleMockRecorder) Log(level, format any, args ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{level, format}, args...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Log", reflect.TypeOf((*MockNetworkFilterConfigHandle)(nil).Log), varargs...) +} diff --git a/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_types.go b/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_types.go new file mode 100644 index 0000000000000..67d300e5ba4d7 --- /dev/null +++ b/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_types.go @@ -0,0 +1,173 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: types.go +// +// Generated by this command: +// +// mockgen -source=types.go -destination=mocks/mock_types.go -package=mocks +// + +// Package mocks is a generated GoMock package. +package mocks + +import ( + reflect "reflect" + + shared "github.com/envoyproxy/envoy/source/extensions/dynamic_modules/sdk/go/shared" + gomock "go.uber.org/mock/gomock" +) + +// MockHttpCalloutCallback is a mock of HttpCalloutCallback interface. +type MockHttpCalloutCallback struct { + ctrl *gomock.Controller + recorder *MockHttpCalloutCallbackMockRecorder + isgomock struct{} +} + +// MockHttpCalloutCallbackMockRecorder is the mock recorder for MockHttpCalloutCallback. +type MockHttpCalloutCallbackMockRecorder struct { + mock *MockHttpCalloutCallback +} + +// NewMockHttpCalloutCallback creates a new mock instance. +func NewMockHttpCalloutCallback(ctrl *gomock.Controller) *MockHttpCalloutCallback { + mock := &MockHttpCalloutCallback{ctrl: ctrl} + mock.recorder = &MockHttpCalloutCallbackMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockHttpCalloutCallback) EXPECT() *MockHttpCalloutCallbackMockRecorder { + return m.recorder +} + +// OnHttpCalloutDone mocks base method. +func (m *MockHttpCalloutCallback) OnHttpCalloutDone(calloutID uint64, result shared.HttpCalloutResult, headers [][2]shared.UnsafeEnvoyBuffer, body []shared.UnsafeEnvoyBuffer) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OnHttpCalloutDone", calloutID, result, headers, body) +} + +// OnHttpCalloutDone indicates an expected call of OnHttpCalloutDone. +func (mr *MockHttpCalloutCallbackMockRecorder) OnHttpCalloutDone(calloutID, result, headers, body any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnHttpCalloutDone", reflect.TypeOf((*MockHttpCalloutCallback)(nil).OnHttpCalloutDone), calloutID, result, headers, body) +} + +// MockHttpStreamCallback is a mock of HttpStreamCallback interface. +type MockHttpStreamCallback struct { + ctrl *gomock.Controller + recorder *MockHttpStreamCallbackMockRecorder + isgomock struct{} +} + +// MockHttpStreamCallbackMockRecorder is the mock recorder for MockHttpStreamCallback. +type MockHttpStreamCallbackMockRecorder struct { + mock *MockHttpStreamCallback +} + +// NewMockHttpStreamCallback creates a new mock instance. +func NewMockHttpStreamCallback(ctrl *gomock.Controller) *MockHttpStreamCallback { + mock := &MockHttpStreamCallback{ctrl: ctrl} + mock.recorder = &MockHttpStreamCallbackMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockHttpStreamCallback) EXPECT() *MockHttpStreamCallbackMockRecorder { + return m.recorder +} + +// OnHttpStreamComplete mocks base method. +func (m *MockHttpStreamCallback) OnHttpStreamComplete(streamID uint64) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OnHttpStreamComplete", streamID) +} + +// OnHttpStreamComplete indicates an expected call of OnHttpStreamComplete. +func (mr *MockHttpStreamCallbackMockRecorder) OnHttpStreamComplete(streamID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnHttpStreamComplete", reflect.TypeOf((*MockHttpStreamCallback)(nil).OnHttpStreamComplete), streamID) +} + +// OnHttpStreamData mocks base method. +func (m *MockHttpStreamCallback) OnHttpStreamData(streamID uint64, body []shared.UnsafeEnvoyBuffer, endStream bool) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OnHttpStreamData", streamID, body, endStream) +} + +// OnHttpStreamData indicates an expected call of OnHttpStreamData. +func (mr *MockHttpStreamCallbackMockRecorder) OnHttpStreamData(streamID, body, endStream any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnHttpStreamData", reflect.TypeOf((*MockHttpStreamCallback)(nil).OnHttpStreamData), streamID, body, endStream) +} + +// OnHttpStreamHeaders mocks base method. +func (m *MockHttpStreamCallback) OnHttpStreamHeaders(streamID uint64, headers [][2]shared.UnsafeEnvoyBuffer, endStream bool) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OnHttpStreamHeaders", streamID, headers, endStream) +} + +// OnHttpStreamHeaders indicates an expected call of OnHttpStreamHeaders. +func (mr *MockHttpStreamCallbackMockRecorder) OnHttpStreamHeaders(streamID, headers, endStream any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnHttpStreamHeaders", reflect.TypeOf((*MockHttpStreamCallback)(nil).OnHttpStreamHeaders), streamID, headers, endStream) +} + +// OnHttpStreamReset mocks base method. +func (m *MockHttpStreamCallback) OnHttpStreamReset(streamID uint64, reason shared.HttpStreamResetReason) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OnHttpStreamReset", streamID, reason) +} + +// OnHttpStreamReset indicates an expected call of OnHttpStreamReset. +func (mr *MockHttpStreamCallbackMockRecorder) OnHttpStreamReset(streamID, reason any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnHttpStreamReset", reflect.TypeOf((*MockHttpStreamCallback)(nil).OnHttpStreamReset), streamID, reason) +} + +// OnHttpStreamTrailers mocks base method. +func (m *MockHttpStreamCallback) OnHttpStreamTrailers(streamID uint64, trailers [][2]shared.UnsafeEnvoyBuffer) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OnHttpStreamTrailers", streamID, trailers) +} + +// OnHttpStreamTrailers indicates an expected call of OnHttpStreamTrailers. +func (mr *MockHttpStreamCallbackMockRecorder) OnHttpStreamTrailers(streamID, trailers any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnHttpStreamTrailers", reflect.TypeOf((*MockHttpStreamCallback)(nil).OnHttpStreamTrailers), streamID, trailers) +} + +// MockScheduler is a mock of Scheduler interface. +type MockScheduler struct { + ctrl *gomock.Controller + recorder *MockSchedulerMockRecorder + isgomock struct{} +} + +// MockSchedulerMockRecorder is the mock recorder for MockScheduler. +type MockSchedulerMockRecorder struct { + mock *MockScheduler +} + +// NewMockScheduler creates a new mock instance. +func NewMockScheduler(ctrl *gomock.Controller) *MockScheduler { + mock := &MockScheduler{ctrl: ctrl} + mock.recorder = &MockSchedulerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockScheduler) EXPECT() *MockSchedulerMockRecorder { + return m.recorder +} + +// Schedule mocks base method. +func (m *MockScheduler) Schedule(arg0 func()) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Schedule", arg0) +} + +// Schedule indicates an expected call of Schedule. +func (mr *MockSchedulerMockRecorder) Schedule(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Schedule", reflect.TypeOf((*MockScheduler)(nil).Schedule), arg0) +} diff --git a/source/extensions/dynamic_modules/sdk/go/shared/network_api.go b/source/extensions/dynamic_modules/sdk/go/shared/network_api.go index 4d8d696973520..3d6342ccf5ea3 100644 --- a/source/extensions/dynamic_modules/sdk/go/shared/network_api.go +++ b/source/extensions/dynamic_modules/sdk/go/shared/network_api.go @@ -1,3 +1,4 @@ +//go:generate mockgen -source=network_api.go -destination=mocks/mock_network_api.go -package=mocks package shared // NetworkFilter is the interface to implement your own network filter logic. diff --git a/source/extensions/dynamic_modules/sdk/go/shared/network_base.go b/source/extensions/dynamic_modules/sdk/go/shared/network_base.go index 7133012e4fda3..018a22ed5a292 100644 --- a/source/extensions/dynamic_modules/sdk/go/shared/network_base.go +++ b/source/extensions/dynamic_modules/sdk/go/shared/network_base.go @@ -1,3 +1,4 @@ +//go:generate mockgen -source=network_base.go -destination=mocks/mock_network_base.go -package=mocks package shared // NetworkBuffer is an interface that provides access to the read and write buffers of a network diff --git a/source/extensions/dynamic_modules/sdk/go/shared/types.go b/source/extensions/dynamic_modules/sdk/go/shared/types.go new file mode 100644 index 0000000000000..bf28c4c76fcfe --- /dev/null +++ b/source/extensions/dynamic_modules/sdk/go/shared/types.go @@ -0,0 +1,336 @@ +//go:generate mockgen -source=types.go -destination=mocks/mock_types.go -package=mocks +package shared + +import ( + "strings" + "unsafe" +) + +// Cross-surface types and interfaces shared by multiple SDK surfaces (HTTP filter, network +// filter, listener filter, access logger, etc.). Surface-specific types live in their own +// files (http.go for HTTP, network.go for network, and so on). + +// UnsafeEnvoyBuffer is a struct that represents a buffer of data from Envoy. +// It contains a pointer to the data and its length. The memory of the data is managed by Envoy. +type UnsafeEnvoyBuffer struct { + // Pointer to the start of the buffer data. + Ptr *byte + // Length of the buffer data in bytes. + Len uint64 +} + +func (b UnsafeEnvoyBuffer) ToUnsafeBytes() []byte { + if b.Ptr == nil || b.Len == 0 { + return nil + } + // Use unsafe to create a byte slice that points to the buffer data without copying. + return unsafe.Slice(b.Ptr, b.Len) +} + +// ToBytes converts the UnsafeEnvoyBuffer to a byte slice. It creates a copy of the data in Go memory. +func (b UnsafeEnvoyBuffer) ToBytes() []byte { + if b.Ptr == nil || b.Len == 0 { + return nil + } + // Create a byte slice that copys the data from the buffer. + owned := make([]byte, b.Len) + // Use unsafe to copy the data from the buffer to the byte slice. + src := unsafe.Slice(b.Ptr, b.Len) + copy(owned, src) + return owned +} + +func (b UnsafeEnvoyBuffer) ToUnsafeString() string { + if b.Ptr == nil || b.Len == 0 { + return "" + } + // Use unsafe to create a string that points to the buffer data without copying. + return unsafe.String(b.Ptr, b.Len) +} + +func (b UnsafeEnvoyBuffer) ToString() string { + if b.Ptr == nil || b.Len == 0 { + return "" + } + return strings.Clone(b.ToUnsafeString()) +} + +// LogLevel is the log level for messages logged via the host environment's logging mechanism. +type LogLevel uint32 + +const ( + LogLevelTrace LogLevel = iota + LogLevelDebug + LogLevelInfo + LogLevelWarn + LogLevelError + LogLevelCritical + LogLevelOff +) + +// MetricID is an opaque identifier for a metric defined via Define{Counter,Gauge,Histogram}. +type MetricID uint64 + +// MetricsResult is the result of a metric definition or update operation. +type MetricsResult uint32 + +const ( + MetricsSuccess MetricsResult = iota + MetricsNotFound + MetricsInvalidTags + MetricsFrozen +) + +// AttributeID identifies an attribute of the current request, response, connection, or upstream +// host that can be retrieved via Get{Attribute,...} family of methods. Corresponds to +// envoy_dynamic_module_type_attribute_id. +type AttributeID uint32 + +const ( + // request.path + AttributeIDRequestPath AttributeID = iota + // request.url_path + AttributeIDRequestUrlPath + // request.host + AttributeIDRequestHost + // request.scheme + AttributeIDRequestScheme + // request.method + AttributeIDRequestMethod + // request.headers + AttributeIDRequestHeaders + // request.referer + AttributeIDRequestReferer + // request.useragent + AttributeIDRequestUserAgent + // request.time + AttributeIDRequestTime + // request.id + AttributeIDRequestId + // request.protocol + AttributeIDRequestProtocol + // request.query + AttributeIDRequestQuery + // request.duration + AttributeIDRequestDuration + // request.size + AttributeIDRequestSize + // request.total_size + AttributeIDRequestTotalSize + // response.code + AttributeIDResponseCode + // response.code_details + AttributeIDResponseCodeDetails + // response.flags + AttributeIDResponseFlags + // response.grpc_status + AttributeIDResponseGrpcStatus + // response.headers + AttributeIDResponseHeaders + // response.trailers + AttributeIDResponseTrailers + // response.size + AttributeIDResponseSize + // response.total_size + AttributeIDResponseTotalSize + // response.backend_latency + AttributeIDResponseBackendLatency + // source.address + AttributeIDSourceAddress + // source.port + AttributeIDSourcePort + // destination.address + AttributeIDDestinationAddress + // destination.port + AttributeIDDestinationPort + // connection.id + AttributeIDConnectionId + // connection.mtls + AttributeIDConnectionMTLS + // connection.requested_server_name + AttributeIDConnectionRequestedServerName + // connection.tls_version + AttributeIDConnectionTLSVersion + // connection.subject_local_certificate + AttributeIDConnectionSubjectLocalCertificate + // connection.subject_peer_certificate + AttributeIDConnectionSubjectPeerCertificate + // connection.dns_san_local_certificate + AttributeIDConnectionDNSSanLocalCertificate + // connection.dns_san_peer_certificate + AttributeIDConnectionDNSSanPeerCertificate + // connection.uri_san_local_certificate + AttributeIDConnectionURISanLocalCertificate + // connection.uri_san_peer_certificate + AttributeIDConnectionURISanPeerCertificate + // connection.sha256_peer_certificate_digest + AttributeIDConnectionSha256PeerCertificateDigest + // connection.transport_failure_reason + AttributeIDConnectionTransportFailureReason + // connection.termination_details + AttributeIDConnectionTerminationDetails + // upstream.address + AttributeIDUpstreamAddress + // upstream.port + AttributeIDUpstreamPort + // upstream.tls_version + AttributeIDUpstreamTLSVersion + // upstream.subject_local_certificate + AttributeIDUpstreamSubjectLocalCertificate + // upstream.subject_peer_certificate + AttributeIDUpstreamSubjectPeerCertificate + // upstream.dns_san_local_certificate + AttributeIDUpstreamDNSSanLocalCertificate + // upstream.dns_san_peer_certificate + AttributeIDUpstreamDNSSanPeerCertificate + // upstream.uri_san_local_certificate + AttributeIDUpstreamURISanLocalCertificate + // upstream.uri_san_peer_certificate + AttributeIDUpstreamURISanPeerCertificate + // upstream.sha256_peer_certificate_digest + AttributeIDUpstreamSha256PeerCertificateDigest + // upstream.local_address + AttributeIDUpstreamLocalAddress + // upstream.transport_failure_reason + AttributeIDUpstreamTransportFailureReason + // upstream.request_attempt_count + AttributeIDUpstreamRequestAttemptCount + // upstream.cx_pool_ready_duration + AttributeIDUpstreamCxPoolReadyDuration + // upstream.locality + AttributeIDUpstreamLocality + // xds.node + AttributeIDXdsNode + // xds.cluster_name + AttributeIDXdsClusterName + // xds.cluster_metadata + AttributeIDXdsClusterMetadata + // xds.listener_direction + AttributeIDXdsListenerDirection + // xds.listener_metadata + AttributeIDXdsListenerMetadata + // xds.route_name + AttributeIDXdsRouteName + // xds.route_metadata + AttributeIDXdsRouteMetadata + // xds.virtual_host_name + AttributeIDXdsVirtualHostName + // xds.virtual_host_metadata + AttributeIDXdsVirtualHostMetadata + // xds.upstream_host_metadata + AttributeIDXdsUpstreamHostMetadata + // xds.filter_chain_name + AttributeIDXdsFilterChainName + // health_check + AttributeIDHealthCheck +) + +// HttpHeaderType identifies which HTTP header map to access. It corresponds to +// envoy_dynamic_module_type_http_header_type. The values match the ABI's enum order: +// RequestHeader, RequestTrailer, ResponseHeader, ResponseTrailer. +type HttpHeaderType uint32 + +const ( + HttpHeaderTypeRequestHeader HttpHeaderType = 0 + HttpHeaderTypeRequestTrailer HttpHeaderType = 1 + HttpHeaderTypeResponseHeader HttpHeaderType = 2 + HttpHeaderTypeResponseTrailer HttpHeaderType = 3 +) + +// HttpCalloutInitResult is the result of initializing an HTTP callout or stream. +type HttpCalloutInitResult uint32 + +const ( + HttpCalloutInitSuccess HttpCalloutInitResult = iota + HttpCalloutInitMissingRequiredHeaders + HttpCalloutInitClusterNotFound + HttpCalloutInitDuplicateCalloutId + HttpCalloutInitCannotCreateRequest +) + +// HttpCalloutResult is the result of a completed HTTP callout (delivered via +// HttpCalloutCallback.OnHttpCalloutDone). +type HttpCalloutResult uint32 + +const ( + HttpCalloutSuccess HttpCalloutResult = iota + HttpCalloutReset + HttpCalloutExceedResponseBufferLimit +) + +// HttpCalloutCallback is the callback interface invoked when an HTTP callout completes. +type HttpCalloutCallback interface { + OnHttpCalloutDone(calloutID uint64, result HttpCalloutResult, + headers [][2]UnsafeEnvoyBuffer, body []UnsafeEnvoyBuffer) +} + +// HttpStreamResetReason is the reason that an HTTP stream (started via StartHttpStream) +// was reset. +type HttpStreamResetReason uint32 + +const ( + HttpStreamResetReasonConnectionFailure HttpStreamResetReason = iota + HttpStreamResetReasonConnectionTermination + HttpStreamResetReasonLocalReset + HttpStreamResetReasonLocalRefusedStreamReset + HttpStreamResetReasonOverflow + HttpStreamResetReasonRemoteReset + HttpStreamResetReasonRemoteRefusedStreamReset + HttpStreamResetReasonProtocolError +) + +// HttpStreamCallback is the callback interface invoked for events on an HTTP stream started +// via StartHttpStream. +type HttpStreamCallback interface { + OnHttpStreamHeaders(streamID uint64, headers [][2]UnsafeEnvoyBuffer, endStream bool) + OnHttpStreamData(streamID uint64, body []UnsafeEnvoyBuffer, endStream bool) + OnHttpStreamTrailers(streamID uint64, trailers [][2]UnsafeEnvoyBuffer) + OnHttpStreamComplete(streamID uint64) + OnHttpStreamReset(streamID uint64, reason HttpStreamResetReason) +} + +// SocketOptionState represents the socket state at which an option should be applied. +// This corresponds to envoy_dynamic_module_type_socket_option_state in the dynamic module ABI. +type SocketOptionState uint32 + +const ( + // SocketOptionStatePrebind applies the option before the socket is bound. + SocketOptionStatePrebind SocketOptionState = iota + // SocketOptionStateBound applies the option after the socket is bound. + SocketOptionStateBound + // SocketOptionStateListening applies the option after the socket starts listening. + SocketOptionStateListening +) + +// SocketDirection represents whether the socket option should be applied to the upstream +// (outgoing to backend) or downstream (incoming from client) connection. +// This corresponds to envoy_dynamic_module_type_socket_direction in the dynamic module ABI. +type SocketDirection uint32 + +const ( + // SocketDirectionUpstream applies the option to the upstream (outgoing) connection. + SocketDirectionUpstream SocketDirection = iota + // SocketDirectionDownstream applies the option to the downstream (incoming) connection. + SocketDirectionDownstream +) + +// ClusterHostCounts carries the host counts returned by HttpFilterHandle.GetClusterHostCounts. +type ClusterHostCounts struct { + // Total is the total number of hosts in the priority set. + Total uint64 + // Healthy is the number of hosts in the HEALTHY state. + Healthy uint64 + // Degraded is the number of hosts in the DEGRADED state. + Degraded uint64 +} + +// Scheduler is the interface that provides scheduling capabilities for asynchronous operations. +// This allow the plugins run tasks in another thread and continue the processing later at the +// thread where the stream plugin is being processed. +type Scheduler interface { + // Schedule schedules a function to be executed asynchronously in the thread where the stream + // plugin is being processed. + // + // NOTE: The function may be ignored if the related plugin processing is completed. + Schedule(func()) +} diff --git a/test/extensions/dynamic_modules/http/BUILD b/test/extensions/dynamic_modules/http/BUILD index 10a3a7812329a..ee843fdf6a6e2 100644 --- a/test/extensions/dynamic_modules/http/BUILD +++ b/test/extensions/dynamic_modules/http/BUILD @@ -90,8 +90,13 @@ envoy_cc_test( deps = [ "//envoy/registry", "//source/common/router:string_accessor_lib", - "//source/extensions/dynamic_modules:abi_impl", - "//source/extensions/filters/http/dynamic_modules:abi_impl", + # The Go SDK's `abi` Go package references every surface's + # `envoy_dynamic_module_callback_*` symbols, so any Go test_data .so has + # unresolved cross-surface callback references. With RTLD_LAZY the loader + # accepts these as long as the test binary provides them. all_abi_impls + # aggregates every per-surface `abi_impl`/`filter_lib`/`*_lib` library so a + # single dep gives the test binary the complete callback symbol surface. + "//source/extensions/dynamic_modules:all_abi_impls", "//source/extensions/filters/http/dynamic_modules:filter_lib", "//test/extensions/dynamic_modules:util", "//test/mocks/http:http_mocks", @@ -150,8 +155,9 @@ envoy_cc_test( }, rbe_pool = "6gig", deps = [ - "//source/extensions/dynamic_modules:abi_impl", - "//source/extensions/filters/http/dynamic_modules:abi_impl", + "//source/common/config:metadata_lib", + # See comment on filter_test above for why we link every per-surface abi_impl. + "//source/extensions/dynamic_modules:all_abi_impls", "//source/extensions/filters/http/dynamic_modules:factory_registration", "//test/extensions/dynamic_modules:util", "//test/extensions/dynamic_modules/test_data/rust:http_integration_test_static", diff --git a/test/extensions/dynamic_modules/http/integration_test.cc b/test/extensions/dynamic_modules/http/integration_test.cc index f800a6aa29ebd..bd2ccff9ee36b 100644 --- a/test/extensions/dynamic_modules/http/integration_test.cc +++ b/test/extensions/dynamic_modules/http/integration_test.cc @@ -1,6 +1,7 @@ #include "envoy/extensions/filters/http/dynamic_modules/v3/dynamic_modules.pb.h" #include "source/common/common/base64.h" +#include "source/common/config/metadata.h" #include "test/extensions/dynamic_modules/util.h" #include "test/integration/http_integration.h" @@ -1024,6 +1025,85 @@ TEST_P(DynamicModulesIntegrationTest, ConfigScheduler) { FAIL() << "Config was not updated in time"; } +// Verifies the config-time HttpCallout API: the filter config Create() initiates a +// callout via HttpFilterConfigHandle.HttpCallout against cluster_0. Per-request filters +// short-circuit with x-config-callout: success once the callout completes +// (503 + "pending" until then). +TEST_P(DynamicModulesIntegrationTest, ConfigCallout) { + // C++ SDK does not expose the config-time callout API; skip. + if (GetParam() == "cpp") { + return; + } + initializeFilter("http_config_callout", "cluster_0"); + codec_client_ = makeHttpConnection(makeClientConnection((lookupPort("http")))); + + // First downstream request: the dispatcher run-loop drives the in-flight config-time + // callout out to cluster_0. Serve it so the callout completes; the factory's atomic + // flag flips on completion. The downstream request itself short-circuits with 503. + { + auto encoder_decoder = codec_client_->startRequest(default_request_headers_); + auto response = std::move(encoder_decoder.second); + waitForNextUpstreamRequest(); + upstream_request_->encodeHeaders(default_response_headers_, true); + ASSERT_TRUE(response->waitForEndStream()); + EXPECT_TRUE(response->complete()); + } + + // Subsequent requests should see "success" once the atomic flag has been observed. + for (int i = 0; i < 20; ++i) { + auto encoder_decoder = codec_client_->startRequest(default_request_headers_); + auto response = std::move(encoder_decoder.second); + ASSERT_TRUE(response->waitForEndStream()); + EXPECT_TRUE(response->complete()); + + auto hdr = response->headers().get(Http::LowerCaseString("x-config-callout")); + ASSERT_FALSE(hdr.empty()); + if (hdr[0]->value().getStringView() == "success") { + return; + } + absl::SleepFor(absl::Milliseconds(50)); + } + FAIL() << "Config callout did not complete in time"; +} + +// Verifies the config-time StartHttpStream API: the filter config Create() opens an HTTP +// stream via HttpFilterConfigHandle.StartHttpStream against cluster_0. Per-request filters +// short-circuit with x-config-stream: success once the stream completes +// (503 + "pending" until then). +TEST_P(DynamicModulesIntegrationTest, ConfigStream) { + // C++ SDK does not expose the config-time stream API; skip. + if (GetParam() == "cpp") { + return; + } + initializeFilter("http_config_stream", "cluster_0"); + codec_client_ = makeHttpConnection(makeClientConnection((lookupPort("http")))); + + // Serve the in-flight config-time stream against cluster_0 on the first request. + { + auto encoder_decoder = codec_client_->startRequest(default_request_headers_); + auto response = std::move(encoder_decoder.second); + waitForNextUpstreamRequest(); + upstream_request_->encodeHeaders(default_response_headers_, true); + ASSERT_TRUE(response->waitForEndStream()); + EXPECT_TRUE(response->complete()); + } + + for (int i = 0; i < 20; ++i) { + auto encoder_decoder = codec_client_->startRequest(default_request_headers_); + auto response = std::move(encoder_decoder.second); + ASSERT_TRUE(response->waitForEndStream()); + EXPECT_TRUE(response->complete()); + + auto hdr = response->headers().get(Http::LowerCaseString("x-config-stream")); + ASSERT_FALSE(hdr.empty()); + if (hdr[0]->value().getStringView() == "success") { + return; + } + absl::SleepFor(absl::Milliseconds(50)); + } + FAIL() << "Config stream did not complete in time"; +} + // Test buffer limit callbacks for non-terminal filters. TEST_P(DynamicModulesIntegrationTest, BufferLimitFilter) { initializeFilter("buffer_limit_filter"); @@ -1106,4 +1186,119 @@ TEST_P(DynamicModulesIntegrationTest, ListMetadataCallbacks) { EXPECT_EQ("false", bool_1[0]->value().getStringView()); } +// Verifies the scalar dynamic-metadata getters and SetMetadata. The route is configured +// with metadata under "test_ns" containing string/number/bool values; the filter reads +// them via Route source, writes them into Dynamic source under a test namespace, and on +// the response side reads them back from Dynamic source and surfaces them via headers. +// +// Verifies: GetMetadataString, GetMetadataNumber, GetMetadataBool, SetMetadata, +// GetMetadataKeys. +TEST_P(DynamicModulesIntegrationTest, DynamicMetadata) { + // C++ SDK doesn't currently surface the same scalar metadata API in its integration + // module; skip. + if (GetParam() == "cpp") { + return; + } + config_helper_.addConfigModifier([](envoy::extensions::filters::network::http_connection_manager:: + v3::HttpConnectionManager& hcm) { + // Add metadata to the (single) route under test_ns. + auto* route = + hcm.mutable_route_config()->mutable_virtual_hosts(0)->mutable_routes(0)->mutable_metadata(); + Envoy::Config::Metadata::mutableMetadataValue(*route, "test_ns", "string_key") + .set_string_value("hello_metadata"); + Envoy::Config::Metadata::mutableMetadataValue(*route, "test_ns", "number_key") + .set_number_value(42.0); + Envoy::Config::Metadata::mutableMetadataValue(*route, "test_ns", "bool_key") + .set_bool_value(true); + }); + initializeFilter("dynamic_metadata"); + + codec_client_ = makeHttpConnection(makeClientConnection((lookupPort("http")))); + auto response = + sendRequestAndWaitForResponse(default_request_headers_, 0, default_response_headers_, 0); + ASSERT_TRUE(response->complete()); + EXPECT_EQ("200", response->headers().Status()->value().getStringView()); + + auto str_hdr = response->headers().get(Http::LowerCaseString("x-dm-string")); + ASSERT_FALSE(str_hdr.empty()); + EXPECT_EQ("hello_metadata", str_hdr[0]->value().getStringView()); + + auto num_hdr = response->headers().get(Http::LowerCaseString("x-dm-number")); + ASSERT_FALSE(num_hdr.empty()); + // The number is float-formatted; "42" is what both Go's strconv.FormatFloat(42, 'f', -1, 64) + // and Rust's f64::to_string(42.0) produce. + EXPECT_EQ("42", num_hdr[0]->value().getStringView()); + + auto bool_hdr = response->headers().get(Http::LowerCaseString("x-dm-bool")); + ASSERT_FALSE(bool_hdr.empty()); + EXPECT_EQ("true", bool_hdr[0]->value().getStringView()); + + // GetMetadataKeys should report exactly the 3 keys we wrote. + auto count_hdr = response->headers().get(Http::LowerCaseString("x-dm-key-count")); + ASSERT_FALSE(count_hdr.empty()); + EXPECT_EQ("3", count_hdr[0]->value().getStringView()); +} + +// Verifies SetFilterState/GetFilterState round-trip across filter boundaries: +// filter_state_writer (configured with "round_trip_value") sets a key on the request +// side; filter_state_reader (chained after) reads it on the request side and surfaces +// it via x-filter-state-value on the response. +TEST_P(DynamicModulesIntegrationTest, FilterStateRoundTrip) { + if (GetParam() == "cpp") { + return; + } + + // Set up the env var first since initializeFilter normally does it but we're going to + // hand-build the filter chain. + std::string module_name = "http_integration_test"; + if (GetParam() != "rust_static") { + TestEnvironment::setEnvVar( + "ENVOY_DYNAMIC_MODULES_SEARCH_PATH", + TestEnvironment::substitute("{{ test_rundir }}/test/extensions/dynamic_modules/test_data/" + + GetParam()), + 1); + } else { + module_name += "_static"; + } + TestEnvironment::setEnvVar("GODEBUG", "cgocheck=0", 1); + + // The reader must run AFTER the writer — prependFilter inserts at the front, so we + // prepend reader first, then writer (which then ends up at the front). + config_helper_.prependFilter(fmt::format(R"EOF( +name: envoy.extensions.filters.http.dynamic_modules +typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.dynamic_modules.v3.DynamicModuleFilter + dynamic_module_config: + name: {} + filter_name: filter_state_reader + filter_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: "" +)EOF", + module_name)); + config_helper_.prependFilter(fmt::format(R"EOF( +name: envoy.extensions.filters.http.dynamic_modules +typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.dynamic_modules.v3.DynamicModuleFilter + dynamic_module_config: + name: {} + filter_name: filter_state_writer + filter_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: round_trip_value +)EOF", + module_name)); + initialize(); + + codec_client_ = makeHttpConnection(makeClientConnection((lookupPort("http")))); + auto response = + sendRequestAndWaitForResponse(default_request_headers_, 0, default_response_headers_, 0); + ASSERT_TRUE(response->complete()); + EXPECT_EQ("200", response->headers().Status()->value().getStringView()); + + auto fs_hdr = response->headers().get(Http::LowerCaseString("x-filter-state-value")); + ASSERT_FALSE(fs_hdr.empty()); + EXPECT_EQ("round_trip_value", fs_hdr[0]->value().getStringView()); +} + } // namespace Envoy diff --git a/test/extensions/dynamic_modules/network/BUILD b/test/extensions/dynamic_modules/network/BUILD index f7a405593dc0e..c6241a4a0ffd6 100644 --- a/test/extensions/dynamic_modules/network/BUILD +++ b/test/extensions/dynamic_modules/network/BUILD @@ -83,8 +83,9 @@ envoy_cc_test( env = {"GODEBUG": "cgocheck=0"}, rbe_pool = "6gig", deps = [ - "//source/extensions/dynamic_modules:abi_impl", - "//source/extensions/filters/http/dynamic_modules:abi_impl", + # See //test/extensions/dynamic_modules/http:filter_test for why every test + # binary that loads a Go test_data .so depends on all_abi_impls. + "//source/extensions/dynamic_modules:all_abi_impls", "//source/extensions/filters/network/dynamic_modules:config", "//source/extensions/filters/network/tcp_proxy:config", "//test/integration:integration_lib", diff --git a/test/extensions/dynamic_modules/network/integration_test.cc b/test/extensions/dynamic_modules/network/integration_test.cc index 47dbd4527f9fe..695ebac69a890 100644 --- a/test/extensions/dynamic_modules/network/integration_test.cc +++ b/test/extensions/dynamic_modules/network/integration_test.cc @@ -258,4 +258,62 @@ TEST_P(DynamicModulesNetworkSdkIntegrationTest, BufferLimits) { tcp_client->close(); } +// Verifies StopIteration + ContinueReading: the filter pauses iteration on the first +// OnRead and schedules a continue; without the resume, the upstream never receives any +// bytes. If StopIteration is broken (e.g. ignored, or ContinueReading is broken), this +// test will hang waiting for waitForData and time out. +// +// The C++ test_data module does not implement this filter shape; this test is +// rust/go-only. +TEST_P(DynamicModulesNetworkSdkIntegrationTest, PauseResume) { + if (GetParam() == "cpp") { + return; + } + initializeSdkFilter("pause_resume"); + + IntegrationTcpClientPtr tcp_client = makeTcpConnection(lookupPort("listener_0")); + ASSERT_TRUE(tcp_client->connected()); + + FakeRawConnectionPtr fake_upstream_connection; + ASSERT_TRUE(fake_upstreams_[0]->waitForRawConnection(fake_upstream_connection)); + + ASSERT_TRUE(tcp_client->write("hello", false)); + ASSERT_TRUE(fake_upstream_connection->waitForData(5)); + + ASSERT_TRUE(tcp_client->write("", true)); + ASSERT_TRUE(fake_upstream_connection->waitForHalfClose()); + ASSERT_TRUE(fake_upstream_connection->close()); + tcp_client->waitForHalfClose(); + tcp_client->close(); +} + +// Verifies the filter can mutate the read buffer (Append/append_read_buffer). The +// upstream should observe "hello|appended" instead of just "hello". +// +// The C++ test_data module does not implement this filter shape; this test is +// rust/go-only. +TEST_P(DynamicModulesNetworkSdkIntegrationTest, DataAppender) { + if (GetParam() == "cpp") { + return; + } + initializeSdkFilter("data_appender"); + + IntegrationTcpClientPtr tcp_client = makeTcpConnection(lookupPort("listener_0")); + ASSERT_TRUE(tcp_client->connected()); + + FakeRawConnectionPtr fake_upstream_connection; + ASSERT_TRUE(fake_upstreams_[0]->waitForRawConnection(fake_upstream_connection)); + + ASSERT_TRUE(tcp_client->write("hello", false)); + // The filter appends "|appended" so the upstream should see 5 + 9 = 14 bytes. + ASSERT_TRUE(fake_upstream_connection->waitForData( + FakeRawConnection::waitForInexactMatch("hello|appended"))); + + ASSERT_TRUE(tcp_client->write("", true)); + ASSERT_TRUE(fake_upstream_connection->waitForHalfClose()); + ASSERT_TRUE(fake_upstream_connection->close()); + tcp_client->waitForHalfClose(); + tcp_client->close(); +} + } // namespace Envoy diff --git a/test/extensions/dynamic_modules/test_data/go/BUILD b/test/extensions/dynamic_modules/test_data/go/BUILD index 20415b8a5fe9c..dea2b95efe7e8 100644 --- a/test/extensions/dynamic_modules/test_data/go/BUILD +++ b/test/extensions/dynamic_modules/test_data/go/BUILD @@ -6,4 +6,6 @@ test_program(name = "http") test_program(name = "http_integration_test") +test_program(name = "http_stream_callouts_test") + test_program(name = "network_integration_test") diff --git a/test/extensions/dynamic_modules/test_data/go/http_integration_test/http_integration_test.go b/test/extensions/dynamic_modules/test_data/go/http_integration_test/http_integration_test.go index 473934a85c4be..58d13315c890e 100644 --- a/test/extensions/dynamic_modules/test_data/go/http_integration_test/http_integration_test.go +++ b/test/extensions/dynamic_modules/test_data/go/http_integration_test/http_integration_test.go @@ -37,6 +37,9 @@ func init() { "http_config_stream": &HttpConfigStreamConfigFactory{}, "http_struct_config": &HttpStructConfigFactory{}, "list_metadata_callbacks": &ListMetadataCallbacksConfigFactory{}, + "dynamic_metadata": &DynamicMetadataConfigFactory{}, + "filter_state_writer": &FilterStateWriterConfigFactory{}, + "filter_state_reader": &FilterStateReaderConfigFactory{}, }) } @@ -1471,3 +1474,157 @@ func (f *ListMetadataCallbacksFilter) OnResponseHeaders(headers shared.HeaderMap return shared.HeadersStatusContinue } + +// ----------------------------------------------------------------------------- +// DynamicMetadata: scalar Get/Set on dynamic metadata. +// +// Reads route metadata (configured by the test driver) and writes it back to dynamic +// metadata. Then writes summary headers so the test can assert via response headers +// that the read+write cycle preserved values. +// ----------------------------------------------------------------------------- + +type DynamicMetadataConfigFactory struct { + shared.EmptyHttpFilterConfigFactory +} + +func (DynamicMetadataConfigFactory) Create(_ shared.HttpFilterConfigHandle, _ []byte) (shared.HttpFilterFactory, error) { + return &DynamicMetadataFilterFactory{}, nil +} + +type DynamicMetadataFilterFactory struct { + shared.EmptyHttpFilterFactory +} + +func (*DynamicMetadataFilterFactory) Create(handle shared.HttpFilterHandle) shared.HttpFilter { + return &DynamicMetadataFilter{handle: handle} +} + +type DynamicMetadataFilter struct { + shared.EmptyHttpFilter + handle shared.HttpFilterHandle +} + +func (f *DynamicMetadataFilter) OnRequestHeaders(_ shared.HeaderMap, _ bool) shared.HeadersStatus { + // Read three scalar values from route metadata (set by the test driver in the + // route config). Then write the same values into dynamic metadata under a + // different namespace so we can read them back on the response side. + if v, ok := f.handle.GetMetadataString(shared.MetadataSourceTypeRoute, "test_ns", "string_key"); ok { + f.handle.SetMetadata("dm_test", "string_key", v.ToString()) + } + if v, ok := f.handle.GetMetadataNumber(shared.MetadataSourceTypeRoute, "test_ns", "number_key"); ok { + f.handle.SetMetadata("dm_test", "number_key", v) + } + if v, ok := f.handle.GetMetadataBool(shared.MetadataSourceTypeRoute, "test_ns", "bool_key"); ok { + f.handle.SetMetadata("dm_test", "bool_key", v) + } + return shared.HeadersStatusContinue +} + +func (f *DynamicMetadataFilter) OnResponseHeaders(headers shared.HeaderMap, _ bool) shared.HeadersStatus { + // Read back from dynamic metadata and surface via response headers. + if v, ok := f.handle.GetMetadataString(shared.MetadataSourceTypeDynamic, "dm_test", "string_key"); ok { + headers.Set("x-dm-string", v.ToString()) + } + if v, ok := f.handle.GetMetadataNumber(shared.MetadataSourceTypeDynamic, "dm_test", "number_key"); ok { + headers.Set("x-dm-number", strconv.FormatFloat(v, 'f', -1, 64)) + } + if v, ok := f.handle.GetMetadataBool(shared.MetadataSourceTypeDynamic, "dm_test", "bool_key"); ok { + if v { + headers.Set("x-dm-bool", "true") + } else { + headers.Set("x-dm-bool", "false") + } + } + + // Surface the keys the SDK reports for our namespace, so we can verify + // GetMetadataKeys works. + keys := f.handle.GetMetadataKeys(shared.MetadataSourceTypeDynamic, "dm_test") + headers.Set("x-dm-key-count", strconv.Itoa(len(keys))) + + return shared.HeadersStatusContinue +} + +// ----------------------------------------------------------------------------- +// FilterState: round-trip across two filters. +// +// filter_state_writer sets a filter-state value on the request side. +// filter_state_reader reads the value on the request side and surfaces it via +// response headers. The test wires both filters in order and asserts the reader +// observed what the writer set. +// ----------------------------------------------------------------------------- + +type FilterStateWriterConfigFactory struct { + shared.EmptyHttpFilterConfigFactory +} + +func (FilterStateWriterConfigFactory) Create(_ shared.HttpFilterConfigHandle, config []byte) (shared.HttpFilterFactory, error) { + // config bytes are the value to write. Empty config = "default_value". + value := string(config) + if value == "" { + value = "default_value" + } + return &FilterStateWriterFilterFactory{value: value}, nil +} + +type FilterStateWriterFilterFactory struct { + shared.EmptyHttpFilterFactory + value string +} + +func (f *FilterStateWriterFilterFactory) Create(handle shared.HttpFilterHandle) shared.HttpFilter { + return &FilterStateWriterFilter{handle: handle, value: f.value} +} + +type FilterStateWriterFilter struct { + shared.EmptyHttpFilter + handle shared.HttpFilterHandle + value string +} + +func (f *FilterStateWriterFilter) OnRequestHeaders(_ shared.HeaderMap, _ bool) shared.HeadersStatus { + f.handle.SetFilterState("test_filter_state_key", []byte(f.value)) + return shared.HeadersStatusContinue +} + +type FilterStateReaderConfigFactory struct { + shared.EmptyHttpFilterConfigFactory +} + +func (FilterStateReaderConfigFactory) Create(_ shared.HttpFilterConfigHandle, _ []byte) (shared.HttpFilterFactory, error) { + return &FilterStateReaderFilterFactory{}, nil +} + +type FilterStateReaderFilterFactory struct { + shared.EmptyHttpFilterFactory +} + +func (*FilterStateReaderFilterFactory) Create(handle shared.HttpFilterHandle) shared.HttpFilter { + return &FilterStateReaderFilter{handle: handle} +} + +type FilterStateReaderFilter struct { + shared.EmptyHttpFilter + handle shared.HttpFilterHandle + // Captured on the request side and re-emitted on the response side because + // filter state may not be preserved exactly the same way for the response + // callbacks of the same stream. + captured string + hasValue bool +} + +func (f *FilterStateReaderFilter) OnRequestHeaders(_ shared.HeaderMap, _ bool) shared.HeadersStatus { + if v, ok := f.handle.GetFilterState("test_filter_state_key"); ok { + f.captured = v.ToString() + f.hasValue = true + } + return shared.HeadersStatusContinue +} + +func (f *FilterStateReaderFilter) OnResponseHeaders(headers shared.HeaderMap, _ bool) shared.HeadersStatus { + if f.hasValue { + headers.Set("x-filter-state-value", f.captured) + } else { + headers.Set("x-filter-state-value", "") + } + return shared.HeadersStatusContinue +} diff --git a/test/extensions/dynamic_modules/test_data/go/http_stream_callouts_test/http_stream_callouts_test.go b/test/extensions/dynamic_modules/test_data/go/http_stream_callouts_test/http_stream_callouts_test.go new file mode 100644 index 0000000000000..52af57164e019 --- /dev/null +++ b/test/extensions/dynamic_modules/test_data/go/http_stream_callouts_test/http_stream_callouts_test.go @@ -0,0 +1,351 @@ +// HTTP stream callouts test module. Mirrors test_data/rust/http_stream_callouts_test.rs. +// +// Exercises the StartHttpStream / SendHttpStreamData / SendHttpStreamTrailers / +// ResetHttpStream API family across five filter shapes: +// +// basic_stream_lifecycle - start, receive headers/data, complete +// bidirectional_streaming - send chunks + trailers, count received chunks +// multiple_streams - 3 concurrent streams +// stream_reset - reset on first headers callback +// upstream_reset - rely on upstream to reset +// +// This module is built but currently has no integration driver — its purpose is to +// exercise the SDK API surface at compile time, paralleling the Rust module of the +// same name. +package main + +import ( + "fmt" + + sdk "github.com/envoyproxy/envoy/source/extensions/dynamic_modules/sdk/go" + _ "github.com/envoyproxy/envoy/source/extensions/dynamic_modules/sdk/go/abi" + "github.com/envoyproxy/envoy/source/extensions/dynamic_modules/sdk/go/shared" +) + +func init() { + sdk.RegisterHttpFilterConfigFactories(map[string]shared.HttpFilterConfigFactory{ + "basic_stream_lifecycle": &basicStreamLifecycleFactory{}, + "bidirectional_streaming": &bidirectionalStreamingFactory{}, + "multiple_streams": &multipleStreamsFactory{}, + "stream_reset": &streamResetFactory{}, + "upstream_reset": &upstreamResetFactory{}, + }) +} + +func main() {} //nolint:all + +// ============================================================================= +// Test 1: Basic Stream Lifecycle +// ============================================================================= + +type basicStreamLifecycleFactory struct { + shared.EmptyHttpFilterConfigFactory +} + +func (basicStreamLifecycleFactory) Create(_ shared.HttpFilterConfigHandle, c []byte) (shared.HttpFilterFactory, error) { + return &basicStreamLifecycleFilterFactory{cluster: string(c)}, nil +} + +type basicStreamLifecycleFilterFactory struct { + shared.EmptyHttpFilterFactory + cluster string +} + +func (f *basicStreamLifecycleFilterFactory) Create(h shared.HttpFilterHandle) shared.HttpFilter { + return &basicStreamLifecycleFilter{handle: h, cluster: f.cluster} +} + +type basicStreamLifecycleFilter struct { + shared.EmptyHttpFilter + handle shared.HttpFilterHandle + cluster string + receivedResponse bool +} + +func (p *basicStreamLifecycleFilter) OnRequestHeaders(_ shared.HeaderMap, _ bool) shared.HeadersStatus { + res, _ := p.handle.StartHttpStream(p.cluster, + [][2]string{{":path", "/test"}, {":method", "GET"}, {"host", "example.com"}}, + nil, true, 5000, p) + if res != shared.HttpCalloutInitSuccess { + p.handle.SendLocalResponse(500, [][2]string{{"x-error", "stream_init_failed"}}, nil, "") + return shared.HeadersStatusStop + } + return shared.HeadersStatusStop +} + +func (p *basicStreamLifecycleFilter) OnHttpStreamHeaders(_ uint64, _ [][2]shared.UnsafeEnvoyBuffer, _ bool) { +} +func (p *basicStreamLifecycleFilter) OnHttpStreamData(_ uint64, _ []shared.UnsafeEnvoyBuffer, _ bool) { +} +func (p *basicStreamLifecycleFilter) OnHttpStreamTrailers(_ uint64, _ [][2]shared.UnsafeEnvoyBuffer) { +} +func (p *basicStreamLifecycleFilter) OnHttpStreamComplete(_ uint64) { + p.receivedResponse = true + p.handle.SendLocalResponse(200, + [][2]string{{"x-stream", "success"}}, + []byte("stream_callout_success"), "") +} +func (p *basicStreamLifecycleFilter) OnHttpStreamReset(_ uint64, _ shared.HttpStreamResetReason) { +} + +// ============================================================================= +// Test 2: Bidirectional Streaming +// ============================================================================= + +type bidirectionalStreamingFactory struct { + shared.EmptyHttpFilterConfigFactory +} + +func (bidirectionalStreamingFactory) Create(_ shared.HttpFilterConfigHandle, c []byte) (shared.HttpFilterFactory, error) { + return &bidirectionalStreamingFilterFactory{cluster: string(c)}, nil +} + +type bidirectionalStreamingFilterFactory struct { + shared.EmptyHttpFilterFactory + cluster string +} + +func (f *bidirectionalStreamingFilterFactory) Create(h shared.HttpFilterHandle) shared.HttpFilter { + return &bidirectionalStreamingFilter{handle: h, cluster: f.cluster} +} + +type bidirectionalStreamingFilter struct { + shared.EmptyHttpFilter + handle shared.HttpFilterHandle + cluster string + streamHandle uint64 + chunksReceived int +} + +func (p *bidirectionalStreamingFilter) OnRequestHeaders(_ shared.HeaderMap, _ bool) shared.HeadersStatus { + res, id := p.handle.StartHttpStream(p.cluster, + [][2]string{ + {":path", "/stream"}, + {":method", "POST"}, + {"host", "example.com"}, + {"content-type", "application/octet-stream"}, + }, + nil, false, 10000, p) + if res != shared.HttpCalloutInitSuccess { + p.handle.SendLocalResponse(500, [][2]string{{"x-error", "stream_init_failed"}}, nil, "") + return shared.HeadersStatusStop + } + p.streamHandle = id + + // Send chunks + trailers. + if !p.handle.SendHttpStreamData(id, []byte("chunk1"), false) { + p.handle.SendLocalResponse(500, [][2]string{{"x-error", "send_chunk1"}}, nil, "") + return shared.HeadersStatusStop + } + if !p.handle.SendHttpStreamData(id, []byte("chunk2"), false) { + p.handle.SendLocalResponse(500, [][2]string{{"x-error", "send_chunk2"}}, nil, "") + return shared.HeadersStatusStop + } + if !p.handle.SendHttpStreamTrailers(id, [][2]string{{"x-trailer", "value"}}) { + p.handle.SendLocalResponse(500, [][2]string{{"x-error", "send_trailers"}}, nil, "") + return shared.HeadersStatusStop + } + + return shared.HeadersStatusStop +} + +func (p *bidirectionalStreamingFilter) OnHttpStreamHeaders(_ uint64, _ [][2]shared.UnsafeEnvoyBuffer, _ bool) { +} +func (p *bidirectionalStreamingFilter) OnHttpStreamData(id uint64, _ []shared.UnsafeEnvoyBuffer, _ bool) { + if id == p.streamHandle { + p.chunksReceived++ + } +} +func (p *bidirectionalStreamingFilter) OnHttpStreamTrailers(_ uint64, _ [][2]shared.UnsafeEnvoyBuffer) { +} +func (p *bidirectionalStreamingFilter) OnHttpStreamComplete(id uint64) { + if id != p.streamHandle { + return + } + p.handle.SendLocalResponse(200, + [][2]string{{"x-chunks-received", fmt.Sprintf("%d", p.chunksReceived)}}, + []byte("bidirectional_success"), "") +} +func (p *bidirectionalStreamingFilter) OnHttpStreamReset(_ uint64, _ shared.HttpStreamResetReason) { +} + +// ============================================================================= +// Test 3: Multiple Streams +// ============================================================================= + +type multipleStreamsFactory struct { + shared.EmptyHttpFilterConfigFactory +} + +func (multipleStreamsFactory) Create(_ shared.HttpFilterConfigHandle, c []byte) (shared.HttpFilterFactory, error) { + return &multipleStreamsFilterFactory{cluster: string(c)}, nil +} + +type multipleStreamsFilterFactory struct { + shared.EmptyHttpFilterFactory + cluster string +} + +func (f *multipleStreamsFilterFactory) Create(h shared.HttpFilterHandle) shared.HttpFilter { + return &multipleStreamsFilter{handle: h, cluster: f.cluster} +} + +type multipleStreamsFilter struct { + shared.EmptyHttpFilter + handle shared.HttpFilterHandle + cluster string + streamHandles []uint64 + completedStreams int +} + +func (p *multipleStreamsFilter) OnRequestHeaders(_ shared.HeaderMap, _ bool) shared.HeadersStatus { + for i := 1; i <= 3; i++ { + path := fmt.Sprintf("/stream%d", i) + res, id := p.handle.StartHttpStream(p.cluster, + [][2]string{{":path", path}, {":method", "GET"}, {"host", "example.com"}}, + nil, true, 5000, p) + if res == shared.HttpCalloutInitSuccess { + p.streamHandles = append(p.streamHandles, id) + } + } + if len(p.streamHandles) != 3 { + p.handle.SendLocalResponse(500, [][2]string{{"x-error", "stream_init_failed"}}, nil, "") + } + return shared.HeadersStatusStop +} + +func (p *multipleStreamsFilter) OnHttpStreamHeaders(_ uint64, _ [][2]shared.UnsafeEnvoyBuffer, _ bool) { +} +func (p *multipleStreamsFilter) OnHttpStreamData(_ uint64, _ []shared.UnsafeEnvoyBuffer, _ bool) { +} +func (p *multipleStreamsFilter) OnHttpStreamTrailers(_ uint64, _ [][2]shared.UnsafeEnvoyBuffer) { +} +func (p *multipleStreamsFilter) OnHttpStreamComplete(id uint64) { + for _, h := range p.streamHandles { + if h == id { + p.completedStreams++ + break + } + } + if p.completedStreams == 3 { + p.handle.SendLocalResponse(200, [][2]string{{"x-stream", "all_success"}}, nil, "") + } +} +func (p *multipleStreamsFilter) OnHttpStreamReset(_ uint64, _ shared.HttpStreamResetReason) {} + +// ============================================================================= +// Test 4: Stream Reset +// ============================================================================= + +type streamResetFactory struct { + shared.EmptyHttpFilterConfigFactory +} + +func (streamResetFactory) Create(_ shared.HttpFilterConfigHandle, c []byte) (shared.HttpFilterFactory, error) { + return &streamResetFilterFactory{cluster: string(c)}, nil +} + +type streamResetFilterFactory struct { + shared.EmptyHttpFilterFactory + cluster string +} + +func (f *streamResetFilterFactory) Create(h shared.HttpFilterHandle) shared.HttpFilter { + return &streamResetFilter{handle: h, cluster: f.cluster} +} + +type streamResetFilter struct { + shared.EmptyHttpFilter + handle shared.HttpFilterHandle + cluster string + streamHandle uint64 + receivedHdrs bool + resetCalled bool +} + +func (p *streamResetFilter) OnRequestHeaders(_ shared.HeaderMap, _ bool) shared.HeadersStatus { + res, id := p.handle.StartHttpStream(p.cluster, + [][2]string{{":path", "/slow"}, {":method", "GET"}, {"host", "example.com"}}, + nil, true, 5000, p) + if res != shared.HttpCalloutInitSuccess { + p.handle.SendLocalResponse(500, [][2]string{{"x-error", "stream_init_failed"}}, nil, "") + return shared.HeadersStatusStop + } + p.streamHandle = id + return shared.HeadersStatusStop +} + +func (p *streamResetFilter) OnHttpStreamHeaders(id uint64, _ [][2]shared.UnsafeEnvoyBuffer, _ bool) { + if id != p.streamHandle { + return + } + p.receivedHdrs = true + // Immediately reset the stream after receiving headers. + p.handle.ResetHttpStream(id) +} +func (p *streamResetFilter) OnHttpStreamData(_ uint64, _ []shared.UnsafeEnvoyBuffer, _ bool) {} +func (p *streamResetFilter) OnHttpStreamTrailers(_ uint64, _ [][2]shared.UnsafeEnvoyBuffer) {} +func (p *streamResetFilter) OnHttpStreamComplete(_ uint64) {} +func (p *streamResetFilter) OnHttpStreamReset(id uint64, _ shared.HttpStreamResetReason) { + if id != p.streamHandle { + return + } + p.resetCalled = true + p.handle.SendLocalResponse(200, + [][2]string{{"x-stream", "reset_ok"}}, + []byte("stream_was_reset"), "") +} + +// ============================================================================= +// Test 5: Upstream Reset +// ============================================================================= + +type upstreamResetFactory struct { + shared.EmptyHttpFilterConfigFactory +} + +func (upstreamResetFactory) Create(_ shared.HttpFilterConfigHandle, c []byte) (shared.HttpFilterFactory, error) { + return &upstreamResetFilterFactory{cluster: string(c)}, nil +} + +type upstreamResetFilterFactory struct { + shared.EmptyHttpFilterFactory + cluster string +} + +func (f *upstreamResetFilterFactory) Create(h shared.HttpFilterHandle) shared.HttpFilter { + return &upstreamResetFilter{handle: h, cluster: f.cluster} +} + +type upstreamResetFilter struct { + shared.EmptyHttpFilter + handle shared.HttpFilterHandle + cluster string + streamHandle uint64 +} + +func (p *upstreamResetFilter) OnRequestHeaders(_ shared.HeaderMap, _ bool) shared.HeadersStatus { + res, id := p.handle.StartHttpStream(p.cluster, + [][2]string{{":path", "/reset"}, {":method", "GET"}, {"host", "example.com"}}, + nil, true, 5000, p) + if res != shared.HttpCalloutInitSuccess { + p.handle.SendLocalResponse(500, [][2]string{{"x-error", "stream_init_failed"}}, nil, "") + return shared.HeadersStatusStop + } + p.streamHandle = id + return shared.HeadersStatusStop +} + +func (p *upstreamResetFilter) OnHttpStreamHeaders(_ uint64, _ [][2]shared.UnsafeEnvoyBuffer, _ bool) { +} +func (p *upstreamResetFilter) OnHttpStreamData(_ uint64, _ []shared.UnsafeEnvoyBuffer, _ bool) {} +func (p *upstreamResetFilter) OnHttpStreamTrailers(_ uint64, _ [][2]shared.UnsafeEnvoyBuffer) {} +func (p *upstreamResetFilter) OnHttpStreamComplete(_ uint64) {} +func (p *upstreamResetFilter) OnHttpStreamReset(id uint64, _ shared.HttpStreamResetReason) { + if id != p.streamHandle { + return + } + p.handle.SendLocalResponse(200, + [][2]string{{"x-reset", "true"}}, + []byte("upstream_reset"), "") +} diff --git a/test/extensions/dynamic_modules/test_data/go/network_integration_test/network_integration_test.go b/test/extensions/dynamic_modules/test_data/go/network_integration_test/network_integration_test.go index 58ed5dfba45c2..f5035d059b6b5 100644 --- a/test/extensions/dynamic_modules/test_data/go/network_integration_test/network_integration_test.go +++ b/test/extensions/dynamic_modules/test_data/go/network_integration_test/network_integration_test.go @@ -12,6 +12,8 @@ func init() { "connection_state": &connectionStateConfigFactory{}, "half_close": &halfCloseConfigFactory{}, "buffer_limits": &bufferLimitsConfigFactory{}, + "pause_resume": &pauseResumeConfigFactory{}, + "data_appender": &dataAppenderConfigFactory{}, }) } @@ -170,3 +172,86 @@ func (f *bufferLimitsFilter) OnNewConnection() shared.NetworkFilterStatus { } return shared.NetworkFilterStatusContinue } + +// ============================================================================= +// pause_resume: returns Stop on the first OnRead call, schedules a ContinueReading +// via the filter scheduler, and lets the data flow normally on subsequent reads. +// +// Verifies that NetworkFilterStatusStop genuinely pauses iteration and that +// ContinueReading from a scheduled task resumes it. Without the resume the +// upstream connection never sees the data and the test would hang. +// ============================================================================= + +type pauseResumeConfigFactory struct { + shared.EmptyNetworkFilterConfigFactory +} + +func (pauseResumeConfigFactory) Create(shared.NetworkFilterConfigHandle, []byte) (shared.NetworkFilterFactory, error) { + return &pauseResumeFactory{}, nil +} + +type pauseResumeFactory struct { + shared.EmptyNetworkFilterFactory +} + +func (*pauseResumeFactory) Create(handle shared.NetworkFilterHandle) shared.NetworkFilter { + return &pauseResumeFilter{handle: handle} +} + +type pauseResumeFilter struct { + shared.EmptyNetworkFilter + handle shared.NetworkFilterHandle + paused bool +} + +func (f *pauseResumeFilter) OnRead(shared.NetworkBuffer, bool) shared.NetworkFilterStatus { + if !f.paused { + f.paused = true + // Schedule the resume on the same worker thread. The scheduler defers the + // continuation until after this OnRead returns; otherwise ContinueReading is + // a no-op since iteration hasn't been paused yet. + f.handle.GetScheduler().Schedule(func() { + f.handle.ContinueReading() + }) + return shared.NetworkFilterStatusStop + } + return shared.NetworkFilterStatusContinue +} + +// ============================================================================= +// data_appender: appends a fixed suffix to every read buffer before letting it +// flow downstream. Verifies ReadBuffer().Append() works end-to-end (the upstream +// must observe the suffix). +// ============================================================================= + +type dataAppenderConfigFactory struct { + shared.EmptyNetworkFilterConfigFactory +} + +func (dataAppenderConfigFactory) Create(shared.NetworkFilterConfigHandle, []byte) (shared.NetworkFilterFactory, error) { + return &dataAppenderFactory{}, nil +} + +type dataAppenderFactory struct { + shared.EmptyNetworkFilterFactory +} + +func (*dataAppenderFactory) Create(handle shared.NetworkFilterHandle) shared.NetworkFilter { + return &dataAppenderFilter{handle: handle} +} + +type dataAppenderFilter struct { + shared.EmptyNetworkFilter + handle shared.NetworkFilterHandle + appended bool +} + +func (f *dataAppenderFilter) OnRead(buf shared.NetworkBuffer, _ bool) shared.NetworkFilterStatus { + // Append once on the first OnRead so the upstream observes the modification. + // Subsequent reads pass through unchanged so we don't keep appending forever. + if !f.appended { + buf.Append([]byte("|appended")) + f.appended = true + } + return shared.NetworkFilterStatusContinue +} diff --git a/test/extensions/dynamic_modules/test_data/go/test_data.bzl b/test/extensions/dynamic_modules/test_data/go/test_data.bzl index 7d4d9beb4aa8a..5040bd2c2d09d 100644 --- a/test/extensions/dynamic_modules/test_data/go/test_data.bzl +++ b/test/extensions/dynamic_modules/test_data/go/test_data.bzl @@ -1,7 +1,14 @@ load("@io_bazel_rules_go//go:def.bzl", "go_binary") -# This declares a cc_library target that is used to build a shared library. -# name + ".c" is the source file that is compiled to create the shared library. +# Builds a Go-based test_data dynamic module as a c-shared .so. +# +# The Go SDK's `abi/*.go` files reference all of Envoy's per-surface +# `envoy_dynamic_module_callback_*` symbols. When a test binary loads the .so but only +# links a subset of the matching `abi_impl` C++ libraries, the unresolved references +# would break dlopen on Linux. The `-Wl,--unresolved-symbols=ignore-all` linker flag +# tells the dynamic linker to allow these unresolved symbols at load time; they're +# resolved lazily when the module actually invokes them, and any genuinely missing +# symbol surfaces as a clear error at first call rather than at dlopen. def test_program(name): go_binary( name = name, @@ -9,6 +16,15 @@ def test_program(name): out = "lib{}.so".format(name), cgo = True, linkmode = "c-shared", + gc_linkopts = select({ + "@platforms//os:linux": [ + "-extldflags=-Wl,--unresolved-symbols=ignore-all", + ], + "@platforms//os:macos": [ + "-extldflags=-Wl,-undefined,dynamic_lookup", + ], + "//conditions:default": [], + }), visibility = ["//visibility:public"], deps = [ "@envoy//source/extensions/dynamic_modules:go_sdk", diff --git a/test/extensions/dynamic_modules/test_data/rust/http_integration_test.rs b/test/extensions/dynamic_modules/test_data/rust/http_integration_test.rs index a97caca92c16a..7eb3191ea5ea1 100644 --- a/test/extensions/dynamic_modules/test_data/rust/http_integration_test.rs +++ b/test/extensions/dynamic_modules/test_data/rust/http_integration_test.rs @@ -136,6 +136,15 @@ fn new_http_filter_config_fn( Some(Box::new(ConfigStreamConfig { stream_done })) }, "list_metadata_callbacks" => Some(Box::new(ListMetadataCallbacksFilterConfig {})), + "dynamic_metadata" => Some(Box::new(DynamicMetadataConfig {})), + "filter_state_writer" => Some(Box::new(FilterStateWriterConfig { + value: if config.is_empty() { + "default_value".to_string() + } else { + String::from_utf8_lossy(config).to_string() + }, + })), + "filter_state_reader" => Some(Box::new(FilterStateReaderConfig {})), _ => panic!("Unknown filter name: {name}"), } } @@ -1929,3 +1938,149 @@ impl HttpFilter for ListMetadataCallbacksFilter { envoy_dynamic_module_type_on_http_filter_response_headers_status::Continue } } + +// ============================================================================= +// DynamicMetadata: scalar Get/Set on dynamic metadata. +// ============================================================================= + +struct DynamicMetadataConfig {} + +impl HttpFilterConfig for DynamicMetadataConfig { + fn new_http_filter(&self, _envoy: &mut EHF) -> Box> { + Box::new(DynamicMetadataFilter {}) + } +} + +struct DynamicMetadataFilter {} + +impl HttpFilter for DynamicMetadataFilter { + fn on_request_headers( + &mut self, + envoy_filter: &mut EHF, + _end_of_stream: bool, + ) -> abi::envoy_dynamic_module_type_on_http_filter_request_headers_status { + use abi::envoy_dynamic_module_type_metadata_source::Route; + + // Get-then-set pattern: the Get* methods return a reference borrowing envoy_filter + // immutably; subsequent Set* calls need a mutable borrow. Materialize values into + // owned forms first so the immutable borrow ends before the mutating calls. + let str_val: Option = envoy_filter + .get_metadata_string(Route, "test_ns", "string_key") + .map(|b| String::from_utf8_lossy(b.as_slice()).to_string()); + let num_val: Option = envoy_filter.get_metadata_number(Route, "test_ns", "number_key"); + let bool_val: Option = envoy_filter.get_metadata_bool(Route, "test_ns", "bool_key"); + + if let Some(s) = str_val { + envoy_filter.set_dynamic_metadata_string("dm_test", "string_key", &s); + } + if let Some(n) = num_val { + envoy_filter.set_dynamic_metadata_number("dm_test", "number_key", n); + } + if let Some(b) = bool_val { + envoy_filter.set_dynamic_metadata_bool("dm_test", "bool_key", b); + } + abi::envoy_dynamic_module_type_on_http_filter_request_headers_status::Continue + } + + fn on_response_headers( + &mut self, + envoy_filter: &mut EHF, + _end_of_stream: bool, + ) -> abi::envoy_dynamic_module_type_on_http_filter_response_headers_status { + use abi::envoy_dynamic_module_type_metadata_source::Dynamic; + + // The metadata getters return references into `envoy_filter`, holding an immutable + // borrow. We must materialize Vec copies before calling the mutating + // `set_response_header` so the borrow checker is satisfied. + let str_val: Option> = envoy_filter + .get_metadata_string(Dynamic, "dm_test", "string_key") + .map(|b| b.as_slice().to_vec()); + let num_val: Option = envoy_filter.get_metadata_number(Dynamic, "dm_test", "number_key"); + let bool_val: Option = envoy_filter.get_metadata_bool(Dynamic, "dm_test", "bool_key"); + let key_count = envoy_filter + .get_metadata_keys(Dynamic, "dm_test") + .map(|v| v.len()) + .unwrap_or(0); + + if let Some(s) = str_val { + envoy_filter.set_response_header("x-dm-string", &s); + } + if let Some(n) = num_val { + envoy_filter.set_response_header("x-dm-number", n.to_string().as_bytes()); + } + if let Some(b) = bool_val { + envoy_filter.set_response_header("x-dm-bool", b.to_string().as_bytes()); + } + envoy_filter.set_response_header("x-dm-key-count", key_count.to_string().as_bytes()); + + abi::envoy_dynamic_module_type_on_http_filter_response_headers_status::Continue + } +} + +// ============================================================================= +// FilterState: round-trip writer + reader. +// ============================================================================= + +struct FilterStateWriterConfig { + value: String, +} + +impl HttpFilterConfig for FilterStateWriterConfig { + fn new_http_filter(&self, _envoy: &mut EHF) -> Box> { + Box::new(FilterStateWriterFilter { + value: self.value.clone(), + }) + } +} + +struct FilterStateWriterFilter { + value: String, +} + +impl HttpFilter for FilterStateWriterFilter { + fn on_request_headers( + &mut self, + envoy_filter: &mut EHF, + _end_of_stream: bool, + ) -> abi::envoy_dynamic_module_type_on_http_filter_request_headers_status { + envoy_filter.set_filter_state_bytes(b"test_filter_state_key", self.value.as_bytes()); + abi::envoy_dynamic_module_type_on_http_filter_request_headers_status::Continue + } +} + +struct FilterStateReaderConfig {} + +impl HttpFilterConfig for FilterStateReaderConfig { + fn new_http_filter(&self, _envoy: &mut EHF) -> Box> { + Box::new(FilterStateReaderFilter { captured: None }) + } +} + +struct FilterStateReaderFilter { + captured: Option>, +} + +impl HttpFilter for FilterStateReaderFilter { + fn on_request_headers( + &mut self, + envoy_filter: &mut EHF, + _end_of_stream: bool, + ) -> abi::envoy_dynamic_module_type_on_http_filter_request_headers_status { + if let Some(buf) = envoy_filter.get_filter_state_bytes(b"test_filter_state_key") { + self.captured = Some(buf.as_slice().to_vec()); + } + abi::envoy_dynamic_module_type_on_http_filter_request_headers_status::Continue + } + + fn on_response_headers( + &mut self, + envoy_filter: &mut EHF, + _end_of_stream: bool, + ) -> abi::envoy_dynamic_module_type_on_http_filter_response_headers_status { + match &self.captured { + Some(v) => envoy_filter.set_response_header("x-filter-state-value", v), + None => envoy_filter.set_response_header("x-filter-state-value", b""), + }; + abi::envoy_dynamic_module_type_on_http_filter_response_headers_status::Continue + } +} diff --git a/test/extensions/dynamic_modules/test_data/rust/network_integration_test.rs b/test/extensions/dynamic_modules/test_data/rust/network_integration_test.rs index 50f1afbe597cb..6e409af622668 100644 --- a/test/extensions/dynamic_modules/test_data/rust/network_integration_test.rs +++ b/test/extensions/dynamic_modules/test_data/rust/network_integration_test.rs @@ -20,6 +20,8 @@ fn new_network_filter_config_fn Some(Box::new(ConnectionStateFilterConfig)), "half_close" => Some(Box::new(HalfCloseFilterConfig)), "buffer_limits" => Some(Box::new(BufferLimitsFilterConfig)), + "pause_resume" => Some(Box::new(PauseResumeFilterConfig)), + "data_appender" => Some(Box::new(DataAppenderFilterConfig)), _ => panic!("unknown filter name: {name}"), } } @@ -303,3 +305,74 @@ impl NetworkFilter for BufferLimitsFilter { BELOW_LOW_WATERMARK_CALLED.store(true, Ordering::SeqCst); } } + +// ============================================================================= +// pause_resume — exercises StopIteration + ContinueReading via the scheduler. +// ============================================================================= + +struct PauseResumeFilterConfig; + +impl NetworkFilterConfig for PauseResumeFilterConfig { + fn new_network_filter(&self, _envoy: &mut ENF) -> Box> { + Box::new(PauseResumeFilter { paused: false }) + } +} + +struct PauseResumeFilter { + paused: bool, +} + +impl NetworkFilter for PauseResumeFilter { + fn on_read( + &mut self, + envoy_filter: &mut ENF, + _data_length: usize, + _end_stream: bool, + ) -> abi::envoy_dynamic_module_type_on_network_filter_data_status { + if !self.paused { + self.paused = true; + // Schedule a continue_reading via the filter scheduler. on_scheduled fires on + // the same worker thread once dispatcher iteration unwinds back. + let scheduler = envoy_filter.new_scheduler(); + scheduler.commit(1); + return abi::envoy_dynamic_module_type_on_network_filter_data_status::StopIteration; + } + abi::envoy_dynamic_module_type_on_network_filter_data_status::Continue + } + + fn on_scheduled(&mut self, envoy_filter: &mut ENF, _event_id: u64) { + envoy_filter.continue_reading(); + } +} + +// ============================================================================= +// data_appender — append a fixed suffix to the read buffer so the upstream +// observes the modification. +// ============================================================================= + +struct DataAppenderFilterConfig; + +impl NetworkFilterConfig for DataAppenderFilterConfig { + fn new_network_filter(&self, _envoy: &mut ENF) -> Box> { + Box::new(DataAppenderFilter { appended: false }) + } +} + +struct DataAppenderFilter { + appended: bool, +} + +impl NetworkFilter for DataAppenderFilter { + fn on_read( + &mut self, + envoy_filter: &mut ENF, + _data_length: usize, + _end_stream: bool, + ) -> abi::envoy_dynamic_module_type_on_network_filter_data_status { + if !self.appended { + envoy_filter.append_read_buffer(b"|appended"); + self.appended = true; + } + abi::envoy_dynamic_module_type_on_network_filter_data_status::Continue + } +} diff --git a/tools/spelling/spelling_dictionary.txt b/tools/spelling/spelling_dictionary.txt index c1125d30480e5..5927574d7fe45 100644 --- a/tools/spelling/spelling_dictionary.txt +++ b/tools/spelling/spelling_dictionary.txt @@ -1709,3 +1709,8 @@ IWYU CRTP bitrate kbps +cgo +cgocheck +dynamicmodulescustom +strconv +formatfloat From 47d93f5db194867106300c8b4d45fa70fd0c51ad Mon Sep 17 00:00:00 2001 From: Adam Anderson <6754028+AdamEAnderson@users.noreply.github.com> Date: Wed, 6 May 2026 23:49:25 +0000 Subject: [PATCH 2/5] fix Signed-off-by: Adam Anderson <6754028+AdamEAnderson@users.noreply.github.com> --- source/extensions/dynamic_modules/BUILD | 15 +- .../dynamic_modules/sdk/go/abi/http.go | 1153 +++++++---------- .../dynamic_modules/sdk/go/abi/network.go | 22 +- .../dynamic_modules/sdk/go/shared/http.go | 504 ++----- .../dynamic_modules/sdk/go/shared/http_api.go | 217 ++++ .../sdk/go/shared/mocks/mock_http.go | 250 ---- .../sdk/go/shared/mocks/mock_http_api.go | 267 ++++ test/extensions/dynamic_modules/http/BUILD | 7 - test/extensions/dynamic_modules/network/BUILD | 2 - .../test_data/go/test_data.bzl | 11 +- 10 files changed, 1127 insertions(+), 1321 deletions(-) create mode 100644 source/extensions/dynamic_modules/sdk/go/shared/http_api.go create mode 100644 source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_http_api.go diff --git a/source/extensions/dynamic_modules/BUILD b/source/extensions/dynamic_modules/BUILD index fe21c4aebac1b..8adb68c5b6890 100644 --- a/source/extensions/dynamic_modules/BUILD +++ b/source/extensions/dynamic_modules/BUILD @@ -49,12 +49,7 @@ envoy_cc_library( alwayslink = True, ) -# A meta-target that aggregates every per-surface abi_impl-style C++ library that -# implements the `envoy_dynamic_module_callback_*` host callbacks. -# -# The Go SDK's `abi/*.go` package is monolithic — importing it pulls in references to -# every surface's callbacks. So a Go test_data .so always references all of them. Tests -# that load such .so files must provide all of those symbols in the test binary's +# Tests that load Go SDK .so files must provide all of those symbols in the test binary's # symbol table; otherwise dlopen's RTLD_LAZY can't resolve them and load fails. This # meta-target lets a test depend on a single line and get every callback the Go SDK # may have referenced. @@ -79,13 +74,11 @@ envoy_cc_library( alwayslink = True, ) -# The shared package is pure Go (no cgo) — interfaces, types, and EmptyXxx no-ops shared -# across the SDK and module code. Modules depend on this transitively via go_sdk and -# go_sdk_abi. go_library( name = "go_sdk_shared", srcs = [ "sdk/go/shared/http.go", + "sdk/go/shared/http_api.go", "sdk/go/shared/network_api.go", "sdk/go/shared/network_base.go", "sdk/go/shared/types.go", @@ -94,8 +87,6 @@ go_library( visibility = ["//visibility:public"], ) -# The top-level sdk package — pure Go. Holds the factory registries and program-handle -# indirection. Imports shared. go_library( name = "go_sdk", srcs = ["sdk/go/sdk.go"], @@ -106,8 +97,6 @@ go_library( ], ) -# The abi package — cgo-heavy. Implements the C-callable trampolines that Envoy invokes -# and the Go-callable wrappers that bridge into Envoy's host callbacks. go_library( name = "go_sdk_abi", srcs = [ diff --git a/source/extensions/dynamic_modules/sdk/go/abi/http.go b/source/extensions/dynamic_modules/sdk/go/abi/http.go index b5d63c3fd92f8..d3701eaaface2 100644 --- a/source/extensions/dynamic_modules/sdk/go/abi/http.go +++ b/source/extensions/dynamic_modules/sdk/go/abi/http.go @@ -198,7 +198,7 @@ func envoyBufferSliceToUnsafeEnvoyBufferSlice( func hostLog(level shared.LogLevel, format string, args []any) { logLevel := uint32(level) - // Quick check if logging is enabled at this level. + // Skip Sprintf if logging at this level is disabled. if !bool(C.envoy_dynamic_module_callback_log_enabled( (C.envoy_dynamic_module_type_log_level)(logLevel), )) { @@ -302,7 +302,7 @@ func (h *dymHeaderMap) Add(key, value string) { } func (h *dymHeaderMap) Remove(key string) { - // The ABI use the set to nil to remove the header. + // The ABI removes a header by setting its value to a null buffer. C.envoy_dynamic_module_callback_http_set_header( (C.envoy_dynamic_module_type_http_filter_envoy_ptr)(h.hostPluginPtr), (C.envoy_dynamic_module_type_http_header_type)(h.headerType), @@ -366,6 +366,204 @@ func (b *dymBodyBuffer) Drain(size uint64) { ) } +// dymSpan implements shared.Span by wrapping the active span pointer for the current stream. +// The pointer is owned by Envoy and must not be finished by the module. filter is retained so +// child spans spawned from this span can be tracked on the owning filter handle and safely +// retired when the stream is destroyed. +type dymSpan struct { + spanPtr C.envoy_dynamic_module_type_span_envoy_ptr + hostPluginPtr C.envoy_dynamic_module_type_http_filter_envoy_ptr + filter *dymHttpFilterHandle +} + +func (s *dymSpan) SetTag(key, value string) { + C.envoy_dynamic_module_callback_http_span_set_tag( + s.spanPtr, + stringToModuleBuffer(key), + stringToModuleBuffer(value), + ) + runtime.KeepAlive(key) + runtime.KeepAlive(value) +} + +func (s *dymSpan) SetOperation(operation string) { + C.envoy_dynamic_module_callback_http_span_set_operation( + s.spanPtr, + stringToModuleBuffer(operation), + ) + runtime.KeepAlive(operation) +} + +func (s *dymSpan) Log(event string) { + C.envoy_dynamic_module_callback_http_span_log( + s.hostPluginPtr, + s.spanPtr, + stringToModuleBuffer(event), + ) + runtime.KeepAlive(event) +} + +func (s *dymSpan) SetSampled(sampled bool) { + C.envoy_dynamic_module_callback_http_span_set_sampled( + s.spanPtr, + (C.bool)(sampled), + ) +} + +func (s *dymSpan) GetBaggage(key string) (shared.UnsafeEnvoyBuffer, bool) { + var valueView C.envoy_dynamic_module_type_envoy_buffer + ret := C.envoy_dynamic_module_callback_http_span_get_baggage( + s.spanPtr, + stringToModuleBuffer(key), + &valueView, + ) + runtime.KeepAlive(key) + if !bool(ret) || valueView.ptr == nil || valueView.length == 0 { + return shared.UnsafeEnvoyBuffer{}, bool(ret) + } + return envoyBufferToUnsafeEnvoyBuffer(valueView), true +} + +func (s *dymSpan) SetBaggage(key, value string) { + C.envoy_dynamic_module_callback_http_span_set_baggage( + s.spanPtr, + stringToModuleBuffer(key), + stringToModuleBuffer(value), + ) + runtime.KeepAlive(key) + runtime.KeepAlive(value) +} + +func (s *dymSpan) GetTraceID() (shared.UnsafeEnvoyBuffer, bool) { + var valueView C.envoy_dynamic_module_type_envoy_buffer + ret := C.envoy_dynamic_module_callback_http_span_get_trace_id( + s.spanPtr, + &valueView, + ) + if !bool(ret) || valueView.ptr == nil || valueView.length == 0 { + return shared.UnsafeEnvoyBuffer{}, bool(ret) + } + return envoyBufferToUnsafeEnvoyBuffer(valueView), true +} + +func (s *dymSpan) GetSpanID() (shared.UnsafeEnvoyBuffer, bool) { + var valueView C.envoy_dynamic_module_type_envoy_buffer + ret := C.envoy_dynamic_module_callback_http_span_get_span_id( + s.spanPtr, + &valueView, + ) + if !bool(ret) || valueView.ptr == nil || valueView.length == 0 { + return shared.UnsafeEnvoyBuffer{}, bool(ret) + } + return envoyBufferToUnsafeEnvoyBuffer(valueView), true +} + +func (s *dymSpan) SpawnChild(operationName string) shared.ChildSpan { + childPtr := C.envoy_dynamic_module_callback_http_span_spawn_child( + s.hostPluginPtr, + s.spanPtr, + stringToModuleBuffer(operationName), + ) + runtime.KeepAlive(operationName) + if childPtr == nil { + return nil + } + child := &dymChildSpan{ + childPtr: childPtr, + hostPluginPtr: s.hostPluginPtr, + filter: s.filter, + } + s.filter.trackChildSpan(child) + return child +} + +// dymChildSpan implements shared.ChildSpan. The module owns the underlying span and should +// call Finish exactly once; the filter destroy hook finishes any spans the module forgot. +type dymChildSpan struct { + childPtr C.envoy_dynamic_module_type_child_span_module_ptr + hostPluginPtr C.envoy_dynamic_module_type_http_filter_envoy_ptr + filter *dymHttpFilterHandle + finished bool +} + +// asSpanPtr returns the child span as the generic span pointer accepted by the span_* callbacks. +// In the ABI both pointer types are void*, and Envoy resolves the right type via dynamic_cast. +func (c *dymChildSpan) asSpanPtr() C.envoy_dynamic_module_type_span_envoy_ptr { + return C.envoy_dynamic_module_type_span_envoy_ptr(c.childPtr) +} + +func (c *dymChildSpan) SetTag(key, value string) { + C.envoy_dynamic_module_callback_http_span_set_tag( + c.asSpanPtr(), + stringToModuleBuffer(key), + stringToModuleBuffer(value), + ) + runtime.KeepAlive(key) + runtime.KeepAlive(value) +} + +func (c *dymChildSpan) SetOperation(operation string) { + C.envoy_dynamic_module_callback_http_span_set_operation( + c.asSpanPtr(), + stringToModuleBuffer(operation), + ) + runtime.KeepAlive(operation) +} + +func (c *dymChildSpan) Log(event string) { + C.envoy_dynamic_module_callback_http_span_log( + c.hostPluginPtr, + c.asSpanPtr(), + stringToModuleBuffer(event), + ) + runtime.KeepAlive(event) +} + +func (c *dymChildSpan) SetSampled(sampled bool) { + C.envoy_dynamic_module_callback_http_span_set_sampled( + c.asSpanPtr(), + (C.bool)(sampled), + ) +} + +func (c *dymChildSpan) SetBaggage(key, value string) { + C.envoy_dynamic_module_callback_http_span_set_baggage( + c.asSpanPtr(), + stringToModuleBuffer(key), + stringToModuleBuffer(value), + ) + runtime.KeepAlive(key) + runtime.KeepAlive(value) +} + +func (c *dymChildSpan) SpawnChild(operationName string) shared.ChildSpan { + childPtr := C.envoy_dynamic_module_callback_http_span_spawn_child( + c.hostPluginPtr, + c.asSpanPtr(), + stringToModuleBuffer(operationName), + ) + runtime.KeepAlive(operationName) + if childPtr == nil { + return nil + } + child := &dymChildSpan{ + childPtr: childPtr, + hostPluginPtr: c.hostPluginPtr, + filter: c.filter, + } + c.filter.trackChildSpan(child) + return child +} + +func (c *dymChildSpan) Finish() { + if c.finished { + return + } + c.finished = true + c.filter.untrackChildSpan(c) + C.envoy_dynamic_module_callback_http_child_span_finish(c.childPtr) +} + type dymHttpFilterHandle struct { hostPluginPtr C.envoy_dynamic_module_type_http_filter_envoy_ptr @@ -383,75 +581,52 @@ type dymHttpFilterHandle struct { streamCompleted bool streamDestroyed bool localResponseSent bool - // nextCalloutID was removed because callout ID is now returned by the host. - // calloutMu guards calloutCallbacks and streamCallbacks. Per-stream HTTP filter - // processing is single-threaded today, so this lock is uncontended in normal use; it's - // held to match the cluster/bootstrap callout maps and to keep the SDK safe if a future - // change introduces cross-thread callout dispatch. - calloutMu sync.Mutex + // calloutCallbacks/streamCallbacks/data are accessed only from the worker thread that + // owns the stream — Envoy invokes filter callbacks and dispatches callout completions + // on the same thread, so no synchronization is needed. calloutCallbacks map[uint64]shared.HttpCalloutCallback streamCallbacks map[uint64]shared.HttpStreamCallback // data backs SetData/GetData — per-stream module-private state for cross-phase // communication. Held in Go memory rather than smuggled through Envoy dynamic metadata // (which would expose the storage to other filters and observers). - dataMu sync.Mutex - data map[string]any + data map[string]any downstreamWatermarkCallbacks shared.DownstreamWatermarkCallbacks - // childSpans tracks unfinished child spans owned by user code so they can be marked - // as finished (without dispatching to Envoy) when the parent stream is destroyed. - // Without this, a finalizer-driven Finish() after stream destroy would invoke - // envoy_dynamic_module_callback_http_child_span_finish against a freed span pointer. - childSpansMu sync.Mutex - childSpans map[*dymChildSpan]struct{} + // childSpans tracks unfinished child spans owned by user code so the stream-destroy hook + // can finish any the module forgot. The host's span pointer stays valid until + // envoy_dynamic_module_callback_http_child_span_finish runs, so finishing orphans here + // is what releases the host-side Tracing::Span — dropping them would leak it. + childSpans map[*dymChildSpan]struct{} } -// trackChildSpan registers a child span so it will be safely retired if the stream is -// destroyed before the module calls Finish on it. +// trackChildSpan registers a child span so it will be finished if the stream is destroyed +// before the module calls Finish on it. func (h *dymHttpFilterHandle) trackChildSpan(c *dymChildSpan) { - h.childSpansMu.Lock() - if h.streamDestroyed { - // Stream is already gone. Mark the child as finished without dispatching to Envoy - // and skip finalizer registration. - h.childSpansMu.Unlock() - c.finishedMu.Lock() - c.finished = true - c.finishedMu.Unlock() - return - } if h.childSpans == nil { h.childSpans = make(map[*dymChildSpan]struct{}) } h.childSpans[c] = struct{}{} - h.childSpansMu.Unlock() - runtime.SetFinalizer(c, func(c *dymChildSpan) { c.Finish() }) } // untrackChildSpan removes a child span from the wrapper's tracking set after the user // calls Finish on it. func (h *dymHttpFilterHandle) untrackChildSpan(c *dymChildSpan) { - h.childSpansMu.Lock() delete(h.childSpans, c) - h.childSpansMu.Unlock() } -// retireChildSpansOnDestroy is called from the stream-destroy hook. It marks every -// unfinished child span as finished (so the finalizer, if any, becomes a no-op) and -// clears the finalizer to release the GC anchor. -func (h *dymHttpFilterHandle) retireChildSpansOnDestroy() { - h.childSpansMu.Lock() - spans := h.childSpans - h.childSpans = nil - h.childSpansMu.Unlock() - for c := range spans { - c.finishedMu.Lock() - c.finished = true - c.finishedMu.Unlock() - runtime.SetFinalizer(c, nil) +// finishChildSpansOnDestroy is called from the stream-destroy hook. It finishes every +// span the module forgot, releasing the host-side Tracing::Span allocations. +func (h *dymHttpFilterHandle) finishChildSpansOnDestroy() { + for c := range h.childSpans { + if !c.finished { + c.finished = true + C.envoy_dynamic_module_callback_http_child_span_finish(c.childPtr) + } } + h.childSpans = nil } func (h *dymHttpFilterHandle) GetMetadataString(source shared.MetadataSourceType, metadataNamespace, key string) (shared.UnsafeEnvoyBuffer, bool) { @@ -648,7 +823,6 @@ func (h *dymHttpFilterHandle) GetMetadataListString(source shared.MetadataSource if !bool(ret) { return shared.UnsafeEnvoyBuffer{}, false } - // Handle the case where the value is empty string. if valueView.ptr == nil || valueView.length == 0 { return shared.UnsafeEnvoyBuffer{}, true } @@ -802,6 +976,21 @@ func (h *dymHttpFilterHandle) GetAttributeBool( return bool(value), true } +func (h *dymHttpFilterHandle) GetFilterStateTyped(key string) (shared.UnsafeEnvoyBuffer, bool) { + var valueView C.envoy_dynamic_module_type_envoy_buffer + + ret := C.envoy_dynamic_module_callback_http_get_filter_state_typed( + h.hostPluginPtr, + stringToModuleBuffer(key), + &valueView, + ) + runtime.KeepAlive(key) + if !bool(ret) || valueView.ptr == nil || valueView.length == 0 { + return shared.UnsafeEnvoyBuffer{}, bool(ret) + } + return envoyBufferToUnsafeEnvoyBuffer(valueView), true +} + func (h *dymHttpFilterHandle) GetFilterState(key string) (shared.UnsafeEnvoyBuffer, bool) { var valueView C.envoy_dynamic_module_type_envoy_buffer @@ -828,18 +1017,22 @@ func (h *dymHttpFilterHandle) SetFilterState(key string, value []byte) { runtime.KeepAlive(value) } +func (h *dymHttpFilterHandle) SetFilterStateTyped(key string, value []byte) bool { + ret := C.envoy_dynamic_module_callback_http_set_filter_state_typed( + h.hostPluginPtr, + stringToModuleBuffer(key), + bytesToModuleBuffer(value), + ) + runtime.KeepAlive(key) + runtime.KeepAlive(value) + return bool(ret) +} + func (h *dymHttpFilterHandle) GetData(key string) any { - h.dataMu.Lock() - defer h.dataMu.Unlock() - if h.data == nil { - return nil - } return h.data[key] } func (h *dymHttpFilterHandle) SetData(key string, value any) { - h.dataMu.Lock() - defer h.dataMu.Unlock() if h.data == nil { h.data = make(map[string]any) } @@ -854,7 +1047,6 @@ func (h *dymHttpFilterHandle) SendLocalResponse( ) { h.localResponseSent = true - // Prepare headers. headerViews := headersToModuleHttpHeaderSlice(headers) C.envoy_dynamic_module_callback_http_send_response( h.hostPluginPtr, @@ -873,7 +1065,6 @@ func (h *dymHttpFilterHandle) SendLocalResponse( func (h *dymHttpFilterHandle) SendResponseHeaders( headers [][2]string, endOfStream bool, ) { - // Prepare headers. headerViews := headersToModuleHttpHeaderSlice(headers) C.envoy_dynamic_module_callback_http_send_response_headers( h.hostPluginPtr, @@ -899,7 +1090,6 @@ func (h *dymHttpFilterHandle) SendResponseData( func (h *dymHttpFilterHandle) SendResponseTrailers( trailers [][2]string, ) { - // Prepare trailers. trailerViews := headersToModuleHttpHeaderSlice(trailers) C.envoy_dynamic_module_callback_http_send_response_trailers( h.hostPluginPtr, @@ -937,348 +1127,24 @@ func (h *dymHttpFilterHandle) RefreshRouteCluster() { C.envoy_dynamic_module_callback_http_clear_route_cluster_cache(h.hostPluginPtr) } -func (h *dymHttpFilterHandle) RequestHeaders() shared.HeaderMap { - return &h.requestHeaderMap -} - -func (h *dymHttpFilterHandle) BufferedRequestBody() shared.BodyBuffer { - return &h.bufferedRequestBody -} - -func (h *dymHttpFilterHandle) ReceivedRequestBody() shared.BodyBuffer { - return &h.receivedRequestBody +func (h *dymHttpFilterHandle) GetWorkerIndex() uint32 { + return uint32(C.envoy_dynamic_module_callback_http_filter_get_worker_index( + h.hostPluginPtr, + )) } -func (h *dymHttpFilterHandle) RequestTrailers() shared.HeaderMap { - return &h.requestTrailerMap -} - -func (h *dymHttpFilterHandle) ResponseHeaders() shared.HeaderMap { - return &h.responseHeaderMap -} - -func (h *dymHttpFilterHandle) BufferedResponseBody() shared.BodyBuffer { - return &h.bufferedResponseBody -} - -func (h *dymHttpFilterHandle) ReceivedResponseBody() shared.BodyBuffer { - return &h.receivedResponseBody -} - -func (h *dymHttpFilterHandle) ReceivedBufferedRequestBody() bool { - return bool(C.envoy_dynamic_module_callback_http_received_buffered_request_body( - h.hostPluginPtr, - )) -} - -func (h *dymHttpFilterHandle) ReceivedBufferedResponseBody() bool { - return bool(C.envoy_dynamic_module_callback_http_received_buffered_response_body( - h.hostPluginPtr, - )) -} - -func (h *dymHttpFilterHandle) ResponseTrailers() shared.HeaderMap { - return &h.responseTrailerMap -} - -func (h *dymHttpFilterHandle) GetMostSpecificConfig() any { - perRoutePtr := C.envoy_dynamic_module_callback_get_most_specific_route_config( - h.hostPluginPtr, - ) - if perRoutePtr != nil { - w := configPerRouteManager.unwrap(unsafe.Pointer(perRoutePtr)) - return w.config - } - return nil -} - -func (h *dymHttpFilterHandle) GetScheduler() shared.Scheduler { - if h.scheduler == nil { - // The scheduler is created lazily and should never be nil - // in practice. But it will be nil in mock tests. - schedulerPtr := C.envoy_dynamic_module_callback_http_filter_scheduler_new( - h.hostPluginPtr) - h.scheduler = newDymScheduler( - unsafe.Pointer(schedulerPtr), - func(schedulerPtr unsafe.Pointer, taskID C.uint64_t) { - C.envoy_dynamic_module_callback_http_filter_scheduler_commit( - (C.envoy_dynamic_module_type_http_filter_scheduler_module_ptr)(schedulerPtr), - taskID, - ) - }, - func(p unsafe.Pointer) { - C.envoy_dynamic_module_callback_http_filter_scheduler_delete( - (C.envoy_dynamic_module_type_http_filter_scheduler_module_ptr)(p), - ) - }, - ) - - // Finalizer is a fallback for the case where the host never invokes the destroy - // hook (e.g., embedded use cases). The synchronous close() in the destroy hook is - // the primary path; once close() runs, schedulerPtr is nil and the finalizer is - // a no-op. - runtime.SetFinalizer(h.scheduler, func(s *dymScheduler) { s.close() }) - } - return h.scheduler -} - -func (h *dymHttpFilterHandle) Log(level shared.LogLevel, format string, args ...any) { - hostLog(level, format, args) -} - -func (h *dymHttpFilterHandle) HttpCallout( - cluster string, headers [][2]string, body []byte, timeoutMs uint64, - cb shared.HttpCalloutCallback) (shared.HttpCalloutInitResult, uint64) { - // Prepare headers. - headerViews := headersToModuleHttpHeaderSlice(headers) - var calloutID C.uint64_t = 0 - - result := C.envoy_dynamic_module_callback_http_filter_http_callout( - h.hostPluginPtr, - &calloutID, - stringToModuleBuffer(cluster), - unsafe.SliceData(headerViews), - (C.size_t)(len(headerViews)), - bytesToModuleBuffer(body), - (C.uint64_t)(timeoutMs), - ) - - runtime.KeepAlive(cluster) - runtime.KeepAlive(headers) - runtime.KeepAlive(body) - runtime.KeepAlive(headerViews) - - goResult := shared.HttpCalloutInitResult(result) - if goResult != shared.HttpCalloutInitSuccess { - return goResult, 0 - } - - h.calloutMu.Lock() - if h.calloutCallbacks == nil { - h.calloutCallbacks = make(map[uint64]shared.HttpCalloutCallback) - } - h.calloutCallbacks[uint64(calloutID)] = cb - h.calloutMu.Unlock() - - return goResult, uint64(calloutID) -} - -func (h *dymHttpFilterHandle) StartHttpStream( - cluster string, headers [][2]string, body []byte, endOfStream bool, timeoutMs uint64, - cb shared.HttpStreamCallback) (shared.HttpCalloutInitResult, uint64) { - // Prepare headers. - headerViews := headersToModuleHttpHeaderSlice(headers) - var streamID C.uint64_t = 0 - - result := C.envoy_dynamic_module_callback_http_filter_start_http_stream( - h.hostPluginPtr, - &streamID, - stringToModuleBuffer(cluster), - unsafe.SliceData(headerViews), - (C.size_t)(len(headerViews)), - bytesToModuleBuffer(body), - (C.bool)(endOfStream), - (C.uint64_t)(timeoutMs), - ) - - runtime.KeepAlive(cluster) - runtime.KeepAlive(headers) - runtime.KeepAlive(body) - runtime.KeepAlive(headerViews) - - goResult := shared.HttpCalloutInitResult(result) - if goResult != shared.HttpCalloutInitSuccess { - return goResult, 0 - } - - h.calloutMu.Lock() - if h.streamCallbacks == nil { - h.streamCallbacks = make(map[uint64]shared.HttpStreamCallback) - } - h.streamCallbacks[uint64(streamID)] = cb - h.calloutMu.Unlock() - - return goResult, uint64(streamID) -} - -func (h *dymHttpFilterHandle) SendHttpStreamData( - streamID uint64, data []byte, endOfStream bool, -) bool { - ret := C.envoy_dynamic_module_callback_http_stream_send_data( - h.hostPluginPtr, - (C.uint64_t)(streamID), - bytesToModuleBuffer(data), - (C.bool)(endOfStream), - ) - runtime.KeepAlive(data) - return bool(ret) -} - -func (h *dymHttpFilterHandle) SendHttpStreamTrailers( - streamID uint64, trailers [][2]string, -) bool { - // Prepare trailers. - trailerViews := headersToModuleHttpHeaderSlice(trailers) - ret := C.envoy_dynamic_module_callback_http_stream_send_trailers( - h.hostPluginPtr, - (C.uint64_t)(streamID), - unsafe.SliceData(trailerViews), - (C.size_t)(len(trailerViews)), - ) - runtime.KeepAlive(trailers) - runtime.KeepAlive(trailerViews) - return bool(ret) -} - -func (h *dymHttpFilterHandle) ResetHttpStream( - streamID uint64, -) { - C.envoy_dynamic_module_callback_http_filter_reset_http_stream( - h.hostPluginPtr, - (C.uint64_t)(streamID), - ) -} - -func (h *dymHttpFilterHandle) SetDownstreamWatermarkCallbacks( - cbs shared.DownstreamWatermarkCallbacks, -) { - h.downstreamWatermarkCallbacks = cbs -} - -func (h *dymHttpFilterHandle) ClearDownstreamWatermarkCallbacks() { - h.downstreamWatermarkCallbacks = nil -} - -func (h *dymHttpFilterHandle) RecordHistogramValue(id shared.MetricID, - value uint64, tagsValues ...string) shared.MetricsResult { - idUint64 := uint64(id) - // Prepare tag values. - tagValueViews := stringArrayToModuleBufferSlice(tagsValues) - - ret := C.envoy_dynamic_module_callback_http_filter_record_histogram_value( - h.hostPluginPtr, - (C.size_t)(idUint64), - unsafe.SliceData(tagValueViews), - (C.size_t)(len(tagValueViews)), - (C.uint64_t)(value), - ) - - runtime.KeepAlive(tagsValues) - runtime.KeepAlive(tagValueViews) - return shared.MetricsResult(ret) -} - -func (h *dymHttpFilterHandle) SetGaugeValue(id shared.MetricID, - value uint64, tagsValues ...string) shared.MetricsResult { - idUint64 := uint64(id) - // Prepare tag values. - tagValueViews := stringArrayToModuleBufferSlice(tagsValues) - - ret := C.envoy_dynamic_module_callback_http_filter_set_gauge( - h.hostPluginPtr, - (C.size_t)(idUint64), - unsafe.SliceData(tagValueViews), - (C.size_t)(len(tagValueViews)), - (C.uint64_t)(value), - ) - - runtime.KeepAlive(tagsValues) - runtime.KeepAlive(tagValueViews) - return shared.MetricsResult(ret) -} - -func (h *dymHttpFilterHandle) IncrementGaugeValue(id shared.MetricID, - value uint64, tagsValues ...string) shared.MetricsResult { - // Prepare tag values. - tagValueViews := stringArrayToModuleBufferSlice(tagsValues) - ret := C.envoy_dynamic_module_callback_http_filter_increment_gauge( - h.hostPluginPtr, - (C.size_t)(uint64(id)), - unsafe.SliceData(tagValueViews), - (C.size_t)(len(tagValueViews)), - (C.uint64_t)(value), - ) - runtime.KeepAlive(tagsValues) - runtime.KeepAlive(tagValueViews) - return shared.MetricsResult(ret) -} - -func (h *dymHttpFilterHandle) DecrementGaugeValue(id shared.MetricID, - value uint64, tagsValues ...string) shared.MetricsResult { - // Prepare tag values. - tagValueViews := stringArrayToModuleBufferSlice(tagsValues) - ret := C.envoy_dynamic_module_callback_http_filter_decrement_gauge( - h.hostPluginPtr, - (C.size_t)(uint64(id)), - unsafe.SliceData(tagValueViews), - (C.size_t)(len(tagValueViews)), - (C.uint64_t)(value), - ) - runtime.KeepAlive(tagsValues) - runtime.KeepAlive(tagValueViews) - return shared.MetricsResult(ret) -} - -func (h *dymHttpFilterHandle) IncrementCounterValue(id shared.MetricID, - value uint64, tagsValues ...string) shared.MetricsResult { - // Prepare tag values. - tagValueViews := stringArrayToModuleBufferSlice(tagsValues) - ret := C.envoy_dynamic_module_callback_http_filter_increment_counter( - h.hostPluginPtr, - (C.size_t)(uint64(id)), - unsafe.SliceData(tagValueViews), - (C.size_t)(len(tagValueViews)), - (C.uint64_t)(value), - ) - runtime.KeepAlive(tagsValues) - runtime.KeepAlive(tagValueViews) - return shared.MetricsResult(ret) -} - -func (h *dymHttpFilterHandle) GetWorkerIndex() uint32 { - return uint32(C.envoy_dynamic_module_callback_http_filter_get_worker_index( - h.hostPluginPtr, - )) -} - -func (h *dymHttpFilterHandle) GetFilterStateTyped(key string) (shared.UnsafeEnvoyBuffer, bool) { - var valueView C.envoy_dynamic_module_type_envoy_buffer - - ret := C.envoy_dynamic_module_callback_http_get_filter_state_typed( - h.hostPluginPtr, - stringToModuleBuffer(key), - &valueView, - ) - runtime.KeepAlive(key) - if !bool(ret) || valueView.ptr == nil || valueView.length == 0 { - return shared.UnsafeEnvoyBuffer{}, bool(ret) - } - return envoyBufferToUnsafeEnvoyBuffer(valueView), true -} - -func (h *dymHttpFilterHandle) SetFilterStateTyped(key string, value []byte) bool { - ret := C.envoy_dynamic_module_callback_http_set_filter_state_typed( - h.hostPluginPtr, - stringToModuleBuffer(key), - bytesToModuleBuffer(value), - ) - runtime.KeepAlive(key) - runtime.KeepAlive(value) - return bool(ret) -} - -func (h *dymHttpFilterHandle) SetSocketOptionInt( - level, name int64, state shared.SocketOptionState, - direction shared.SocketDirection, value int64, -) bool { - return bool(C.envoy_dynamic_module_callback_http_set_socket_option_int( - h.hostPluginPtr, - (C.int64_t)(level), - (C.int64_t)(name), - (C.envoy_dynamic_module_type_socket_option_state)(state), - (C.envoy_dynamic_module_type_socket_direction)(direction), - (C.int64_t)(value), - )) +func (h *dymHttpFilterHandle) SetSocketOptionInt( + level, name int64, state shared.SocketOptionState, + direction shared.SocketDirection, value int64, +) bool { + return bool(C.envoy_dynamic_module_callback_http_set_socket_option_int( + h.hostPluginPtr, + (C.int64_t)(level), + (C.int64_t)(name), + (C.envoy_dynamic_module_type_socket_option_state)(state), + (C.envoy_dynamic_module_type_socket_direction)(direction), + (C.int64_t)(value), + )) } func (h *dymHttpFilterHandle) SetSocketOptionBytes( @@ -1438,225 +1304,282 @@ func (h *dymHttpFilterHandle) RecreateStream(headers [][2]string) bool { return bool(ret) } -// dymSpan implements shared.Span by wrapping the active span pointer for the current stream. -// The pointer is owned by Envoy and must not be finished by the module. filter is retained so -// child spans spawned from this span can be tracked on the owning filter handle and safely -// retired when the stream is destroyed. -type dymSpan struct { - spanPtr C.envoy_dynamic_module_type_span_envoy_ptr - hostPluginPtr C.envoy_dynamic_module_type_http_filter_envoy_ptr - filter *dymHttpFilterHandle +func (h *dymHttpFilterHandle) RequestHeaders() shared.HeaderMap { + return &h.requestHeaderMap } -func (s *dymSpan) SetTag(key, value string) { - C.envoy_dynamic_module_callback_http_span_set_tag( - s.spanPtr, - stringToModuleBuffer(key), - stringToModuleBuffer(value), - ) - runtime.KeepAlive(key) - runtime.KeepAlive(value) +func (h *dymHttpFilterHandle) BufferedRequestBody() shared.BodyBuffer { + return &h.bufferedRequestBody } -func (s *dymSpan) SetOperation(operation string) { - C.envoy_dynamic_module_callback_http_span_set_operation( - s.spanPtr, - stringToModuleBuffer(operation), - ) - runtime.KeepAlive(operation) +func (h *dymHttpFilterHandle) ReceivedRequestBody() shared.BodyBuffer { + return &h.receivedRequestBody } -func (s *dymSpan) Log(event string) { - C.envoy_dynamic_module_callback_http_span_log( - s.hostPluginPtr, - s.spanPtr, - stringToModuleBuffer(event), +func (h *dymHttpFilterHandle) RequestTrailers() shared.HeaderMap { + return &h.requestTrailerMap +} + +func (h *dymHttpFilterHandle) ResponseHeaders() shared.HeaderMap { + return &h.responseHeaderMap +} + +func (h *dymHttpFilterHandle) BufferedResponseBody() shared.BodyBuffer { + return &h.bufferedResponseBody +} + +func (h *dymHttpFilterHandle) ReceivedResponseBody() shared.BodyBuffer { + return &h.receivedResponseBody +} + +func (h *dymHttpFilterHandle) ReceivedBufferedRequestBody() bool { + return bool(C.envoy_dynamic_module_callback_http_received_buffered_request_body( + h.hostPluginPtr, + )) +} + +func (h *dymHttpFilterHandle) ReceivedBufferedResponseBody() bool { + return bool(C.envoy_dynamic_module_callback_http_received_buffered_response_body( + h.hostPluginPtr, + )) +} + +func (h *dymHttpFilterHandle) ResponseTrailers() shared.HeaderMap { + return &h.responseTrailerMap +} + +func (h *dymHttpFilterHandle) GetMostSpecificConfig() any { + perRoutePtr := C.envoy_dynamic_module_callback_get_most_specific_route_config( + h.hostPluginPtr, ) - runtime.KeepAlive(event) + if perRoutePtr != nil { + w := configPerRouteManager.unwrap(unsafe.Pointer(perRoutePtr)) + return w.config + } + return nil } -func (s *dymSpan) SetSampled(sampled bool) { - C.envoy_dynamic_module_callback_http_span_set_sampled( - s.spanPtr, - (C.bool)(sampled), +func (h *dymHttpFilterHandle) GetScheduler() shared.Scheduler { + if h.scheduler == nil { + schedulerPtr := C.envoy_dynamic_module_callback_http_filter_scheduler_new( + h.hostPluginPtr) + h.scheduler = newDymScheduler( + unsafe.Pointer(schedulerPtr), + func(schedulerPtr unsafe.Pointer, taskID C.uint64_t) { + C.envoy_dynamic_module_callback_http_filter_scheduler_commit( + (C.envoy_dynamic_module_type_http_filter_scheduler_module_ptr)(schedulerPtr), + taskID, + ) + }, + func(p unsafe.Pointer) { + C.envoy_dynamic_module_callback_http_filter_scheduler_delete( + (C.envoy_dynamic_module_type_http_filter_scheduler_module_ptr)(p), + ) + }, + ) + } + return h.scheduler +} + +func (h *dymHttpFilterHandle) Log(level shared.LogLevel, format string, args ...any) { + hostLog(level, format, args) +} + +func (h *dymHttpFilterHandle) HttpCallout( + cluster string, headers [][2]string, body []byte, timeoutMs uint64, + cb shared.HttpCalloutCallback) (shared.HttpCalloutInitResult, uint64) { + headerViews := headersToModuleHttpHeaderSlice(headers) + var calloutID C.uint64_t = 0 + + result := C.envoy_dynamic_module_callback_http_filter_http_callout( + h.hostPluginPtr, + &calloutID, + stringToModuleBuffer(cluster), + unsafe.SliceData(headerViews), + (C.size_t)(len(headerViews)), + bytesToModuleBuffer(body), + (C.uint64_t)(timeoutMs), ) + + runtime.KeepAlive(cluster) + runtime.KeepAlive(headers) + runtime.KeepAlive(body) + runtime.KeepAlive(headerViews) + + goResult := shared.HttpCalloutInitResult(result) + if goResult != shared.HttpCalloutInitSuccess { + return goResult, 0 + } + + if h.calloutCallbacks == nil { + h.calloutCallbacks = make(map[uint64]shared.HttpCalloutCallback) + } + h.calloutCallbacks[uint64(calloutID)] = cb + + return goResult, uint64(calloutID) } -func (s *dymSpan) GetBaggage(key string) (shared.UnsafeEnvoyBuffer, bool) { - var valueView C.envoy_dynamic_module_type_envoy_buffer - ret := C.envoy_dynamic_module_callback_http_span_get_baggage( - s.spanPtr, - stringToModuleBuffer(key), - &valueView, +func (h *dymHttpFilterHandle) StartHttpStream( + cluster string, headers [][2]string, body []byte, endOfStream bool, timeoutMs uint64, + cb shared.HttpStreamCallback) (shared.HttpCalloutInitResult, uint64) { + headerViews := headersToModuleHttpHeaderSlice(headers) + var streamID C.uint64_t = 0 + + result := C.envoy_dynamic_module_callback_http_filter_start_http_stream( + h.hostPluginPtr, + &streamID, + stringToModuleBuffer(cluster), + unsafe.SliceData(headerViews), + (C.size_t)(len(headerViews)), + bytesToModuleBuffer(body), + (C.bool)(endOfStream), + (C.uint64_t)(timeoutMs), ) - runtime.KeepAlive(key) - if !bool(ret) || valueView.ptr == nil || valueView.length == 0 { - return shared.UnsafeEnvoyBuffer{}, bool(ret) + + runtime.KeepAlive(cluster) + runtime.KeepAlive(headers) + runtime.KeepAlive(body) + runtime.KeepAlive(headerViews) + + goResult := shared.HttpCalloutInitResult(result) + if goResult != shared.HttpCalloutInitSuccess { + return goResult, 0 } - return envoyBufferToUnsafeEnvoyBuffer(valueView), true -} -func (s *dymSpan) SetBaggage(key, value string) { - C.envoy_dynamic_module_callback_http_span_set_baggage( - s.spanPtr, - stringToModuleBuffer(key), - stringToModuleBuffer(value), - ) - runtime.KeepAlive(key) - runtime.KeepAlive(value) + if h.streamCallbacks == nil { + h.streamCallbacks = make(map[uint64]shared.HttpStreamCallback) + } + h.streamCallbacks[uint64(streamID)] = cb + + return goResult, uint64(streamID) } -func (s *dymSpan) GetTraceID() (shared.UnsafeEnvoyBuffer, bool) { - var valueView C.envoy_dynamic_module_type_envoy_buffer - ret := C.envoy_dynamic_module_callback_http_span_get_trace_id( - s.spanPtr, - &valueView, +func (h *dymHttpFilterHandle) SendHttpStreamData( + streamID uint64, data []byte, endOfStream bool, +) bool { + ret := C.envoy_dynamic_module_callback_http_stream_send_data( + h.hostPluginPtr, + (C.uint64_t)(streamID), + bytesToModuleBuffer(data), + (C.bool)(endOfStream), ) - if !bool(ret) || valueView.ptr == nil || valueView.length == 0 { - return shared.UnsafeEnvoyBuffer{}, bool(ret) - } - return envoyBufferToUnsafeEnvoyBuffer(valueView), true + runtime.KeepAlive(data) + return bool(ret) } -func (s *dymSpan) GetSpanID() (shared.UnsafeEnvoyBuffer, bool) { - var valueView C.envoy_dynamic_module_type_envoy_buffer - ret := C.envoy_dynamic_module_callback_http_span_get_span_id( - s.spanPtr, - &valueView, +func (h *dymHttpFilterHandle) SendHttpStreamTrailers( + streamID uint64, trailers [][2]string, +) bool { + trailerViews := headersToModuleHttpHeaderSlice(trailers) + ret := C.envoy_dynamic_module_callback_http_stream_send_trailers( + h.hostPluginPtr, + (C.uint64_t)(streamID), + unsafe.SliceData(trailerViews), + (C.size_t)(len(trailerViews)), ) - if !bool(ret) || valueView.ptr == nil || valueView.length == 0 { - return shared.UnsafeEnvoyBuffer{}, bool(ret) - } - return envoyBufferToUnsafeEnvoyBuffer(valueView), true + runtime.KeepAlive(trailers) + runtime.KeepAlive(trailerViews) + return bool(ret) } -func (s *dymSpan) SpawnChild(operationName string) shared.ChildSpan { - childPtr := C.envoy_dynamic_module_callback_http_span_spawn_child( - s.hostPluginPtr, - s.spanPtr, - stringToModuleBuffer(operationName), +func (h *dymHttpFilterHandle) ResetHttpStream( + streamID uint64, +) { + C.envoy_dynamic_module_callback_http_filter_reset_http_stream( + h.hostPluginPtr, + (C.uint64_t)(streamID), ) - runtime.KeepAlive(operationName) - if childPtr == nil { - return nil - } - child := &dymChildSpan{ - childPtr: childPtr, - hostPluginPtr: s.hostPluginPtr, - filter: s.filter, - } - // trackChildSpan installs the GC finalizer (so a forgotten Finish is recovered) AND - // records the child on the filter so we can safely retire it if the stream is destroyed - // before the module finishes the span. - if s.filter != nil { - s.filter.trackChildSpan(child) - } else { - runtime.SetFinalizer(child, func(c *dymChildSpan) { c.Finish() }) - } - return child } -// dymChildSpan implements shared.ChildSpan. The module owns the underlying span and must call -// Finish exactly once. Finish is also installed as a finalizer to avoid leaks if the module -// forgets. filter, when non-nil, is the owning filter handle: it tracks unfinished children -// so they can be marked finished (without invoking Envoy) when the stream is destroyed. -type dymChildSpan struct { - childPtr C.envoy_dynamic_module_type_child_span_module_ptr - hostPluginPtr C.envoy_dynamic_module_type_http_filter_envoy_ptr - filter *dymHttpFilterHandle - finishedMu sync.Mutex - finished bool +func (h *dymHttpFilterHandle) SetDownstreamWatermarkCallbacks( + cbs shared.DownstreamWatermarkCallbacks, +) { + h.downstreamWatermarkCallbacks = cbs } -// asSpanPtr returns the child span as the generic span pointer accepted by the span_* callbacks. -// In the ABI both pointer types are void*, and Envoy resolves the right type via dynamic_cast. -func (c *dymChildSpan) asSpanPtr() C.envoy_dynamic_module_type_span_envoy_ptr { - return C.envoy_dynamic_module_type_span_envoy_ptr(c.childPtr) +func (h *dymHttpFilterHandle) ClearDownstreamWatermarkCallbacks() { + h.downstreamWatermarkCallbacks = nil } -func (c *dymChildSpan) SetTag(key, value string) { - C.envoy_dynamic_module_callback_http_span_set_tag( - c.asSpanPtr(), - stringToModuleBuffer(key), - stringToModuleBuffer(value), - ) - runtime.KeepAlive(key) - runtime.KeepAlive(value) -} +func (h *dymHttpFilterHandle) RecordHistogramValue(id shared.MetricID, + value uint64, tagsValues ...string) shared.MetricsResult { + idUint64 := uint64(id) + tagValueViews := stringArrayToModuleBufferSlice(tagsValues) -func (c *dymChildSpan) SetOperation(operation string) { - C.envoy_dynamic_module_callback_http_span_set_operation( - c.asSpanPtr(), - stringToModuleBuffer(operation), + ret := C.envoy_dynamic_module_callback_http_filter_record_histogram_value( + h.hostPluginPtr, + (C.size_t)(idUint64), + unsafe.SliceData(tagValueViews), + (C.size_t)(len(tagValueViews)), + (C.uint64_t)(value), ) - runtime.KeepAlive(operation) -} -func (c *dymChildSpan) Log(event string) { - C.envoy_dynamic_module_callback_http_span_log( - c.hostPluginPtr, - c.asSpanPtr(), - stringToModuleBuffer(event), - ) - runtime.KeepAlive(event) + runtime.KeepAlive(tagsValues) + runtime.KeepAlive(tagValueViews) + return shared.MetricsResult(ret) } -func (c *dymChildSpan) SetSampled(sampled bool) { - C.envoy_dynamic_module_callback_http_span_set_sampled( - c.asSpanPtr(), - (C.bool)(sampled), +func (h *dymHttpFilterHandle) SetGaugeValue(id shared.MetricID, + value uint64, tagsValues ...string) shared.MetricsResult { + idUint64 := uint64(id) + tagValueViews := stringArrayToModuleBufferSlice(tagsValues) + + ret := C.envoy_dynamic_module_callback_http_filter_set_gauge( + h.hostPluginPtr, + (C.size_t)(idUint64), + unsafe.SliceData(tagValueViews), + (C.size_t)(len(tagValueViews)), + (C.uint64_t)(value), ) + + runtime.KeepAlive(tagsValues) + runtime.KeepAlive(tagValueViews) + return shared.MetricsResult(ret) } -func (c *dymChildSpan) SetBaggage(key, value string) { - C.envoy_dynamic_module_callback_http_span_set_baggage( - c.asSpanPtr(), - stringToModuleBuffer(key), - stringToModuleBuffer(value), +func (h *dymHttpFilterHandle) IncrementGaugeValue(id shared.MetricID, + value uint64, tagsValues ...string) shared.MetricsResult { + tagValueViews := stringArrayToModuleBufferSlice(tagsValues) + ret := C.envoy_dynamic_module_callback_http_filter_increment_gauge( + h.hostPluginPtr, + (C.size_t)(uint64(id)), + unsafe.SliceData(tagValueViews), + (C.size_t)(len(tagValueViews)), + (C.uint64_t)(value), ) - runtime.KeepAlive(key) - runtime.KeepAlive(value) + runtime.KeepAlive(tagsValues) + runtime.KeepAlive(tagValueViews) + return shared.MetricsResult(ret) } -func (c *dymChildSpan) SpawnChild(operationName string) shared.ChildSpan { - childPtr := C.envoy_dynamic_module_callback_http_span_spawn_child( - c.hostPluginPtr, - c.asSpanPtr(), - stringToModuleBuffer(operationName), +func (h *dymHttpFilterHandle) DecrementGaugeValue(id shared.MetricID, + value uint64, tagsValues ...string) shared.MetricsResult { + tagValueViews := stringArrayToModuleBufferSlice(tagsValues) + ret := C.envoy_dynamic_module_callback_http_filter_decrement_gauge( + h.hostPluginPtr, + (C.size_t)(uint64(id)), + unsafe.SliceData(tagValueViews), + (C.size_t)(len(tagValueViews)), + (C.uint64_t)(value), ) - runtime.KeepAlive(operationName) - if childPtr == nil { - return nil - } - child := &dymChildSpan{ - childPtr: childPtr, - hostPluginPtr: c.hostPluginPtr, - filter: c.filter, - } - if c.filter != nil { - c.filter.trackChildSpan(child) - } else { - runtime.SetFinalizer(child, func(c *dymChildSpan) { c.Finish() }) - } - return child + runtime.KeepAlive(tagsValues) + runtime.KeepAlive(tagValueViews) + return shared.MetricsResult(ret) } -func (c *dymChildSpan) Finish() { - c.finishedMu.Lock() - if c.finished { - c.finishedMu.Unlock() - return - } - c.finished = true - c.finishedMu.Unlock() - // Drop from the filter's tracking set BEFORE dispatching so a concurrent stream destroy - // won't double-process this span. - if c.filter != nil { - c.filter.untrackChildSpan(c) - } - C.envoy_dynamic_module_callback_http_child_span_finish(c.childPtr) - // Clear the finalizer so the GC anchor is released; harmless if no finalizer was set. - runtime.SetFinalizer(c, nil) +func (h *dymHttpFilterHandle) IncrementCounterValue(id shared.MetricID, + value uint64, tagsValues ...string) shared.MetricsResult { + tagValueViews := stringArrayToModuleBufferSlice(tagsValues) + ret := C.envoy_dynamic_module_callback_http_filter_increment_counter( + h.hostPluginPtr, + (C.size_t)(uint64(id)), + unsafe.SliceData(tagValueViews), + (C.size_t)(len(tagValueViews)), + (C.uint64_t)(value), + ) + runtime.KeepAlive(tagsValues) + runtime.KeepAlive(tagValueViews) + return shared.MetricsResult(ret) } func newDymStreamPluginHandle( @@ -1702,9 +1625,8 @@ func newDymStreamPluginHandle( type dymConfigHandle struct { hostConfigPtr C.envoy_dynamic_module_type_http_filter_config_envoy_ptr - // Config-context callouts can complete on a different thread than the one that started - // them, so callout/stream maps need explicit synchronization. - calloutMu sync.Mutex + // calloutCallbacks/streamCallbacks are accessed only on the main thread — config-level + // callouts both initiate and complete via main_thread_dispatcher_, so no locking needed. calloutCallbacks map[uint64]shared.HttpCalloutCallback streamCallbacks map[uint64]shared.HttpStreamCallback scheduler *dymScheduler @@ -1716,7 +1638,6 @@ func (h *dymConfigHandle) Log(level shared.LogLevel, format string, args ...any) func (h *dymConfigHandle) DefineHistogram(name string, tagKeys ...string) (shared.MetricID, shared.MetricsResult) { - // Prepare tag keys. tagKeyViews := stringArrayToModuleBufferSlice(tagKeys) var metricID C.size_t = 0 @@ -1742,7 +1663,6 @@ func (h *dymConfigHandle) DefineHistogram(name string, func (h *dymConfigHandle) DefineGauge(name string, tagKeys ...string) (shared.MetricID, shared.MetricsResult) { - // Prepare tag keys. tagKeyViews := stringArrayToModuleBufferSlice(tagKeys) var metricID C.size_t = 0 @@ -1767,7 +1687,6 @@ func (h *dymConfigHandle) DefineGauge(name string, func (h *dymConfigHandle) DefineCounter(name string, tagKeys ...string) (shared.MetricID, shared.MetricsResult) { - // Prepare tag keys. tagKeyViews := stringArrayToModuleBufferSlice(tagKeys) var metricID C.size_t = 0 @@ -1816,12 +1735,10 @@ func (h *dymConfigHandle) HttpCallout( return goResult, 0 } - h.calloutMu.Lock() if h.calloutCallbacks == nil { h.calloutCallbacks = make(map[uint64]shared.HttpCalloutCallback) } h.calloutCallbacks[uint64(calloutID)] = cb - h.calloutMu.Unlock() return goResult, uint64(calloutID) } @@ -1853,12 +1770,10 @@ func (h *dymConfigHandle) StartHttpStream( return goResult, 0 } - h.calloutMu.Lock() if h.streamCallbacks == nil { h.streamCallbacks = make(map[uint64]shared.HttpStreamCallback) } h.streamCallbacks[uint64(streamID)] = cb - h.calloutMu.Unlock() return goResult, uint64(streamID) } @@ -1896,8 +1811,6 @@ func (h *dymConfigHandle) ResetHttpStream(streamID uint64) { func (h *dymConfigHandle) GetScheduler() shared.Scheduler { if h.scheduler == nil { - // The scheduler is created lazily and should never be nil - // in practice. But it will be nil in mock tests. schedulerPtr := C.envoy_dynamic_module_callback_http_filter_config_scheduler_new( h.hostConfigPtr) h.scheduler = newDymScheduler( @@ -1914,9 +1827,6 @@ func (h *dymConfigHandle) GetScheduler() shared.Scheduler { ) }, ) - - // See dymHttpFilterHandle.GetScheduler for why the finalizer is a fallback. - runtime.SetFinalizer(h.scheduler, func(s *dymScheduler) { s.close() }) } return h.scheduler } @@ -1979,8 +1889,6 @@ func envoy_dynamic_module_on_http_filter_config_destroy( return } if factoryWrapper.configHandle.scheduler != nil { - // See bootstrap config destroy for why we close synchronously instead of - // dropping the reference and waiting for the GC finalizer. factoryWrapper.configHandle.scheduler.close() factoryWrapper.configHandle.scheduler = nil } @@ -1996,7 +1904,6 @@ func envoy_dynamic_module_on_http_filter_per_route_config_new( nameStr := envoyBufferToStringUnsafe(name) configBytes := envoyBufferToBytesCopy(config) - // The route config handle only make logging available. configHandle := &dymRouteConfigHandle{} configFactory := sdk.GetHttpFilterConfigFactory(nameStr) @@ -2038,8 +1945,6 @@ func envoy_dynamic_module_on_http_filter_new( return nil } - // Create the plugin wrapper. - pluginWrapper := newDymStreamPluginHandle(hostPluginPtr) pluginWrapper.plugin = factoryWrapper.pluginFactory.Create(pluginWrapper) pluginPtr := pluginManager.record(pluginWrapper) @@ -2054,12 +1959,8 @@ func envoy_dynamic_module_on_http_filter_destroy( if pluginWrapper == nil || pluginWrapper.streamDestroyed { return } - // Mark destroyed FIRST so a concurrent SpawnChild seen via trackChildSpan won't register - // a new finalizer that would later fire against a freed span pointer. - pluginWrapper.childSpansMu.Lock() pluginWrapper.streamDestroyed = true - pluginWrapper.childSpansMu.Unlock() - pluginWrapper.retireChildSpansOnDestroy() + pluginWrapper.finishChildSpansOnDestroy() if pluginWrapper.plugin != nil { pluginWrapper.plugin.OnDestroy() } @@ -2072,7 +1973,6 @@ func envoy_dynamic_module_on_http_filter_request_headers( pluginPtr C.envoy_dynamic_module_type_http_filter_module_ptr, endOfStream C.bool, ) C.envoy_dynamic_module_type_on_http_filter_request_headers_status { - // Get the plugin wrapper. pluginWrapper := pluginManager.unwrap(unsafe.Pointer(pluginPtr)) if pluginWrapper == nil || pluginWrapper.plugin == nil { return 0 @@ -2161,7 +2061,6 @@ func envoy_dynamic_module_on_http_filter_stream_complete( } pluginWrapper.streamCompleted = true if pluginWrapper.scheduler != nil { - // See bootstrap config destroy for why we close synchronously. pluginWrapper.scheduler.close() pluginWrapper.scheduler = nil } @@ -2199,17 +2098,12 @@ func envoy_dynamic_module_on_http_filter_http_callout_done( return } - // Prepare headers and body chunks. resultHeaders := envoyHttpHeaderSliceToUnsafeHeaderSlice(unsafe.Slice(headers, int(headersSize))) resultChunks := envoyBufferSliceToUnsafeEnvoyBufferSlice(unsafe.Slice(chunks, int(chunksSize))) - pluginWrapper.calloutMu.Lock() cb := pluginWrapper.calloutCallbacks[uint64(calloutID)] if cb != nil { delete(pluginWrapper.calloutCallbacks, uint64(calloutID)) - } - pluginWrapper.calloutMu.Unlock() - if cb != nil { cb.OnHttpCalloutDone(uint64(calloutID), shared.HttpCalloutResult(result), resultHeaders, @@ -2232,13 +2126,9 @@ func envoy_dynamic_module_on_http_filter_http_stream_headers( return } - // Prepare headers. resultHeaders := envoyHttpHeaderSliceToUnsafeHeaderSlice(unsafe.Slice(headers, int(headersSize))) - pluginWrapper.calloutMu.Lock() - cb := pluginWrapper.streamCallbacks[uint64(streamID)] - pluginWrapper.calloutMu.Unlock() - if cb != nil { + if cb := pluginWrapper.streamCallbacks[uint64(streamID)]; cb != nil { cb.OnHttpStreamHeaders(uint64(streamID), resultHeaders, bool(endOfStream)) } } @@ -2257,13 +2147,9 @@ func envoy_dynamic_module_on_http_filter_http_stream_data( return } - // Prepare data. resultData := envoyBufferSliceToUnsafeEnvoyBufferSlice(unsafe.Slice(chunks, int(chunksSize))) - pluginWrapper.calloutMu.Lock() - cb := pluginWrapper.streamCallbacks[uint64(streamID)] - pluginWrapper.calloutMu.Unlock() - if cb != nil { + if cb := pluginWrapper.streamCallbacks[uint64(streamID)]; cb != nil { cb.OnHttpStreamData(uint64(streamID), resultData, bool(endOfStream)) } } @@ -2281,13 +2167,9 @@ func envoy_dynamic_module_on_http_filter_http_stream_trailers( return } - // Prepare trailers. resultTrailers := envoyHttpHeaderSliceToUnsafeHeaderSlice(unsafe.Slice(trailers, int(trailersSize))) - pluginWrapper.calloutMu.Lock() - cb := pluginWrapper.streamCallbacks[uint64(streamID)] - pluginWrapper.calloutMu.Unlock() - if cb != nil { + if cb := pluginWrapper.streamCallbacks[uint64(streamID)]; cb != nil { cb.OnHttpStreamTrailers(uint64(streamID), resultTrailers) } } @@ -2303,13 +2185,9 @@ func envoy_dynamic_module_on_http_filter_http_stream_complete( return } - pluginWrapper.calloutMu.Lock() cb := pluginWrapper.streamCallbacks[uint64(streamID)] if cb != nil { delete(pluginWrapper.streamCallbacks, uint64(streamID)) - } - pluginWrapper.calloutMu.Unlock() - if cb != nil { cb.OnHttpStreamComplete(uint64(streamID)) } } @@ -2326,13 +2204,9 @@ func envoy_dynamic_module_on_http_filter_http_stream_reset( return } - pluginWrapper.calloutMu.Lock() cb := pluginWrapper.streamCallbacks[uint64(streamID)] if cb != nil { delete(pluginWrapper.streamCallbacks, uint64(streamID)) - } - pluginWrapper.calloutMu.Unlock() - if cb != nil { cb.OnHttpStreamReset(uint64(streamID), shared.HttpStreamResetReason(reason)) } } @@ -2410,13 +2284,9 @@ func envoy_dynamic_module_on_http_filter_config_http_callout_done( resultHeaders := envoyHttpHeaderSliceToUnsafeHeaderSlice(unsafe.Slice(headers, int(headersSize))) resultChunks := envoyBufferSliceToUnsafeEnvoyBufferSlice(unsafe.Slice(chunks, int(chunksSize))) - ch.calloutMu.Lock() cb := ch.calloutCallbacks[uint64(calloutID)] if cb != nil { delete(ch.calloutCallbacks, uint64(calloutID)) - } - ch.calloutMu.Unlock() - if cb != nil { cb.OnHttpCalloutDone(uint64(calloutID), shared.HttpCalloutResult(result), resultHeaders, resultChunks) } } @@ -2438,10 +2308,7 @@ func envoy_dynamic_module_on_http_filter_config_http_stream_headers( resultHeaders := envoyHttpHeaderSliceToUnsafeHeaderSlice(unsafe.Slice(headers, int(headersSize))) - ch.calloutMu.Lock() - cb := ch.streamCallbacks[uint64(streamID)] - ch.calloutMu.Unlock() - if cb != nil { + if cb := ch.streamCallbacks[uint64(streamID)]; cb != nil { cb.OnHttpStreamHeaders(uint64(streamID), resultHeaders, bool(endOfStream)) } } @@ -2463,10 +2330,7 @@ func envoy_dynamic_module_on_http_filter_config_http_stream_data( resultData := envoyBufferSliceToUnsafeEnvoyBufferSlice(unsafe.Slice(chunks, int(chunksSize))) - ch.calloutMu.Lock() - cb := ch.streamCallbacks[uint64(streamID)] - ch.calloutMu.Unlock() - if cb != nil { + if cb := ch.streamCallbacks[uint64(streamID)]; cb != nil { cb.OnHttpStreamData(uint64(streamID), resultData, bool(endOfStream)) } } @@ -2487,10 +2351,7 @@ func envoy_dynamic_module_on_http_filter_config_http_stream_trailers( resultTrailers := envoyHttpHeaderSliceToUnsafeHeaderSlice(unsafe.Slice(trailers, int(trailersSize))) - ch.calloutMu.Lock() - cb := ch.streamCallbacks[uint64(streamID)] - ch.calloutMu.Unlock() - if cb != nil { + if cb := ch.streamCallbacks[uint64(streamID)]; cb != nil { cb.OnHttpStreamTrailers(uint64(streamID), resultTrailers) } } @@ -2507,13 +2368,9 @@ func envoy_dynamic_module_on_http_filter_config_http_stream_complete( } ch := configWrapper.configHandle - ch.calloutMu.Lock() cb := ch.streamCallbacks[uint64(streamID)] if cb != nil { delete(ch.streamCallbacks, uint64(streamID)) - } - ch.calloutMu.Unlock() - if cb != nil { cb.OnHttpStreamComplete(uint64(streamID)) } } @@ -2531,13 +2388,9 @@ func envoy_dynamic_module_on_http_filter_config_http_stream_reset( } ch := configWrapper.configHandle - ch.calloutMu.Lock() cb := ch.streamCallbacks[uint64(streamID)] if cb != nil { delete(ch.streamCallbacks, uint64(streamID)) - } - ch.calloutMu.Unlock() - if cb != nil { cb.OnHttpStreamReset(uint64(streamID), shared.HttpStreamResetReason(reason)) } } diff --git a/source/extensions/dynamic_modules/sdk/go/abi/network.go b/source/extensions/dynamic_modules/sdk/go/abi/network.go index 94b7e6826ea0f..1759b20146326 100644 --- a/source/extensions/dynamic_modules/sdk/go/abi/network.go +++ b/source/extensions/dynamic_modules/sdk/go/abi/network.go @@ -9,7 +9,6 @@ import "C" import ( "runtime" - "sync" "unsafe" sdk "github.com/envoyproxy/envoy/source/extensions/dynamic_modules/sdk/go" @@ -133,11 +132,8 @@ type dymNetworkFilterHandle struct { plugin shared.NetworkFilter readBuffer dymNetworkBuffer writeBuffer dymNetworkBuffer - // calloutMu guards calloutCallbacks. Per-connection network filter processing is - // single-threaded today, so this lock is uncontended in normal use; it's held for - // consistency with cluster/bootstrap callout maps and to keep the SDK safe if a future - // change introduces cross-thread callout dispatch. - calloutMu sync.Mutex + // calloutCallbacks is accessed only from the worker thread that owns the connection — + // Envoy invokes filter callbacks and dispatches callout completions on the same thread. calloutCallbacks map[uint64]shared.HttpCalloutCallback scheduler *dymScheduler filterDestroyed bool @@ -673,12 +669,10 @@ func (h *dymNetworkFilterHandle) HttpCallout( return goResult, 0 } - h.calloutMu.Lock() if h.calloutCallbacks == nil { h.calloutCallbacks = make(map[uint64]shared.HttpCalloutCallback) } h.calloutCallbacks[uint64(calloutID)] = cb - h.calloutMu.Unlock() return goResult, uint64(calloutID) } @@ -891,9 +885,6 @@ func (h *dymNetworkFilterHandle) GetScheduler() shared.Scheduler { ) }, ) - - // Finalizer is a fallback; the destroy hook should call close() synchronously. - runtime.SetFinalizer(h.scheduler, func(s *dymScheduler) { s.close() }) } return h.scheduler } @@ -965,9 +956,6 @@ func (h *dymNetworkConfigHandle) GetScheduler() shared.Scheduler { ) }, ) - - // Finalizer is a fallback; the destroy hook should call close() synchronously. - runtime.SetFinalizer(h.scheduler, func(s *dymScheduler) { s.close() }) } return h.scheduler } @@ -1010,7 +998,6 @@ func envoy_dynamic_module_on_network_filter_config_destroy( return } if configWrapper.configHandle.scheduler != nil { - // See bootstrap config destroy for why we close synchronously. configWrapper.configHandle.scheduler.close() configWrapper.configHandle.scheduler = nil } @@ -1119,7 +1106,6 @@ func envoy_dynamic_module_on_network_filter_destroy( } filterWrapper.filterDestroyed = true if filterWrapper.scheduler != nil { - // See bootstrap config destroy for why we close synchronously. filterWrapper.scheduler.close() filterWrapper.scheduler = nil } @@ -1149,13 +1135,9 @@ func envoy_dynamic_module_on_network_filter_http_callout_done( resultHeaders := envoyHttpHeaderSliceToUnsafeHeaderSlice(unsafe.Slice(headers, int(headersSize))) resultChunks := envoyBufferSliceToUnsafeEnvoyBufferSlice(unsafe.Slice(chunks, int(chunksSize))) - filterWrapper.calloutMu.Lock() cb := filterWrapper.calloutCallbacks[uint64(calloutID)] if cb != nil { delete(filterWrapper.calloutCallbacks, uint64(calloutID)) - } - filterWrapper.calloutMu.Unlock() - if cb != nil { cb.OnHttpCalloutDone(uint64(calloutID), shared.HttpCalloutResult(result), resultHeaders, resultChunks) } } diff --git a/source/extensions/dynamic_modules/sdk/go/shared/http.go b/source/extensions/dynamic_modules/sdk/go/shared/http.go index c26ec22577b3f..ffcfcda1d0de2 100644 --- a/source/extensions/dynamic_modules/sdk/go/shared/http.go +++ b/source/extensions/dynamic_modules/sdk/go/shared/http.go @@ -1,227 +1,13 @@ //go:generate mockgen -source=http.go -destination=mocks/mock_http.go -package=mocks package shared -// HTTP filter SDK surface for dynamic modules. +// HTTP filter SDK surface for dynamic modules — handle, buffer, header, span, and watermark +// types used by the user-facing interfaces in http_api.go. // // Cross-surface primitives (UnsafeEnvoyBuffer, LogLevel, MetricID, AttributeID, Scheduler, // HttpCalloutInitResult/Result/Callback, HttpStreamCallback/ResetReason, SocketOption*, // ClusterHostCounts, HttpHeaderType) live in types.go. -type HeadersStatus int32 - -const ( - // '2' is preserved for ContinueAndDontEndStream and is not exposed here. - - // HeadersStatusContinue indicates that the headers can continue to be processed by - // next plugin in the chain and nothing will be stopped. - HeadersStatusContinue HeadersStatus = 0 - // HeadersStatusStop indicates that the headers processing should stop at this plugin. - // And when the body or trailers are received, the onRequestBody or onRequestTrailers - // of this plugin will be called. And the filter chain will continue or still hang - // based on the returned status of onRequestBody or onRequestTrailers. - // Of course the continueRequestStream or continueResponseStream can be called to continue - // the processing manually. - HeadersStatusStop HeadersStatus = 1 - // HeadersStatusStopAndBuffer indicates that the headers processing should stop at this plugin. - // And even if the body or trailers are received, the onRequestBody or onRequestTrailers - // of this plugin will NOT be called and the body will be buffered. The only way to continue - // the processing is to call continueRequestStream or continueResponseStream manually. - // This is useful when you want to wait a certain condition to be met before continuing - // the processing (For example, waiting for the result of an asynchronous operation). - HeadersStatusStopAllAndBuffer HeadersStatus = 3 - // Similar to HeadersStatusStopAllAndBuffer. But when there are too big body data buffered, - // the HeadersStatusStopAllAndBuffer will result in 413 (Payload Too Large) response to the - // client. But with this status, the watermarking will be used to disable reading from client - // or server. - HeadersStatusStopAllAndWatermark HeadersStatus = 4 - HeadersStatusDefault HeadersStatus = HeadersStatusContinue -) - -type BodyStatus int32 - -const ( - // BodyStatusContinue indicates that the body can continue to be processed by next plugin - // in the chain. And if the onRequestHeaders or onResponseHeaders of this plugin returned - // HeadersStatusStop before, the headers processing will continue. - BodyStatusContinue BodyStatus = 0 - // BodyStatusStopAndBuffer indicates that the body processing should stop at this plugin. - // And the body will be buffered. - BodyStatusStopAndBuffer BodyStatus = 1 - // BodyStatusStopAndWatermark indicates that the body processing should stop at this plugin. - // And watermarking will be used to disable reading from client or server if there are too - // big body data buffered. - BodyStatusStopAndWatermark BodyStatus = 2 - // BodyStatusStopNoBuffer indicates that the body processing should stop at this plugin. - // No body data will be buffered. - BodyStatusStopNoBuffer BodyStatus = 3 - BodyStatusDefault BodyStatus = BodyStatusContinue -) - -type TrailersStatus int32 - -const ( - // TrailersStatusContinue indicates that the trailers can continue to be processed by next plugin - // in the chain. And if the onRequestHeaders, onResponseHeaders, onRequestBody or onResponseBody - // of this plugin have returned stop status before, the processing will continue after this. - TrailersStatusContinue TrailersStatus = 0 - // TrailersStatusStop indicates that the trailers processing should stop at this plugin. The - // only way to continue the processing is to call continueRequestStream or continueResponseStream - // manually. - TrailersStatusStop TrailersStatus = 1 - TrailersStatusDefault TrailersStatus = TrailersStatusContinue -) - -// LocalReplyStatus is returned from HttpFilter.OnLocalReply to control whether Envoy should -// send the local reply to the client or reset the stream instead. -type LocalReplyStatus int32 - -const ( - // LocalReplyStatusContinue indicates that the local reply should continue to be sent - // after all filters are informed. - LocalReplyStatusContinue LocalReplyStatus = 0 - // LocalReplyStatusContinueAndResetStream indicates that the local reply notification - // should continue to all filters, but the stream should be reset instead of sending - // the local reply. - LocalReplyStatusContinueAndResetStream LocalReplyStatus = 1 - LocalReplyStatusDefault LocalReplyStatus = LocalReplyStatusContinue -) - -// HttpFilter is the interface to implement your own plugin logic. This is a simplified version and could -// not implement flexible stream control. But it should be enough for most of the use cases. -type HttpFilter interface { - // OnRequestHeaders will be called when the request headers are received. - // Returns the status to control the plugin chain processing. - OnRequestHeaders(headers HeaderMap, endOfStream bool) HeadersStatus - - // OnRequestBody will be called when the request body are received. This may be called multiple times. - // Returns the status to control the plugin chain processing. - OnRequestBody(body BodyBuffer, endOfStream bool) BodyStatus - - // OnRequestTrailers will be called when the request trailers are received. - // Returns the status to control the plugin chain processing. - OnRequestTrailers(trailers HeaderMap) TrailersStatus - - // OnResponseHeaders will be called when the response headers are received. - // Returns the status to control the plugin chain processing. - OnResponseHeaders(headers HeaderMap, endOfStream bool) HeadersStatus - - // OnResponseBody will be called when the response body is received. This may be called multiple - // times. - // Returns the status to control the plugin chain processing. - OnResponseBody(body BodyBuffer, endOfStream bool) BodyStatus - - // OnResponseTrailers will be called when the response trailers are received. - // Returns the status to control the plugin chain processing. - OnResponseTrailers(trailers HeaderMap) TrailersStatus - - // OnStreamComplete is called when the stream processing is complete and before access logs - // are flushed. - // This is a good place to do any final processing or cleanup before the request is fully - // completed. - OnStreamComplete() - - // OnDestroy is called when the HTTP filter instance is being destroyed. This is called - // after OnStreamComplete and access logs are flushed. This is a good place to release - // any per-stream resources. - OnDestroy() - - // OnLocalReply is called when a local reply is being sent. The filter can either let the - // reply proceed (LocalReplyStatusContinue) or ask Envoy to reset the stream instead - // (LocalReplyStatusContinueAndResetStream). This is invoked before the reply leaves - // Envoy and before any stream reset. - // - // details is a short description of why the local reply is being sent (e.g. - // "buffer overflow", "rate limit exceeded"). The buffer aliases Envoy memory; copy - // before retaining past this call. resetImminent is true if Envoy is going to reset - // the stream after this call. - OnLocalReply(responseCode uint32, details UnsafeEnvoyBuffer, resetImminent bool) LocalReplyStatus -} - -type EmptyHttpFilter struct { -} - -func (p *EmptyHttpFilter) OnRequestHeaders(headers HeaderMap, endOfStream bool) HeadersStatus { - return HeadersStatusDefault -} - -func (p *EmptyHttpFilter) OnRequestBody(body BodyBuffer, endOfStream bool) BodyStatus { - return BodyStatusDefault -} - -func (p *EmptyHttpFilter) OnRequestTrailers(trailers HeaderMap) TrailersStatus { - return TrailersStatusDefault -} - -func (p *EmptyHttpFilter) OnResponseHeaders(headers HeaderMap, endOfStream bool) HeadersStatus { - return HeadersStatusDefault -} - -func (p *EmptyHttpFilter) OnResponseBody(body BodyBuffer, endOfStream bool) BodyStatus { - return BodyStatusDefault -} - -func (p *EmptyHttpFilter) OnResponseTrailers(trailers HeaderMap) TrailersStatus { - return TrailersStatusDefault -} - -func (p *EmptyHttpFilter) OnStreamComplete() { -} - -func (p *EmptyHttpFilter) OnLocalReply(_ uint32, _ UnsafeEnvoyBuffer, _ bool) LocalReplyStatus { - return LocalReplyStatusDefault -} - -func (p *EmptyHttpFilter) OnDestroy() { -} - -// HttpFilterFactory is the factory interface for creating stream plugins. -// This is used to create instances of the stream plugin at runtime when a new request is received. -// The implementation of this interface should be thread-safe and hold the parsed configuration. -type HttpFilterFactory interface { - // Create creates a HttpFilter instance. - Create(handle HttpFilterHandle) HttpFilter - - // OnDestroy is called when the factory is being destroyed. This is a good place to clean up any - // resources. This usually happens when the configuration is updated and all existing streams - // using this factory are closed. - OnDestroy() -} - -type EmptyHttpFilterFactory struct { -} - -func (f *EmptyHttpFilterFactory) Create(handle HttpFilterHandle) HttpFilter { - return &EmptyHttpFilter{} -} - -func (f *EmptyHttpFilterFactory) OnDestroy() { -} - -// HttpFilterConfigFactory is the factory interface for creating stream plugin configurations. -// This is used to create -// PluginConfig based on the unparsed configuration. The HttpFilterConfigFactory should parse the unparsedConfig -// and create a PluginFactory instance. -// The implementation of this interface should be thread-safe and be stateless in most cases. -type HttpFilterConfigFactory interface { - // Create creates a HttpFilterFactory based on the unparsed configuration. - Create(handle HttpFilterConfigHandle, unparsedConfig []byte) (HttpFilterFactory, error) - - // CreatePerRoute creates a per-route configuration based on the unparsed configuration. - CreatePerRoute(unparsedConfig []byte) (any, error) -} - -type EmptyHttpFilterConfigFactory struct { -} - -func (f *EmptyHttpFilterConfigFactory) Create(handle HttpFilterConfigHandle, - unparsedConfig []byte) (HttpFilterFactory, error) { - return &EmptyHttpFilterFactory{}, nil -} - -func (f *EmptyHttpFilterConfigFactory) CreatePerRoute(unparsedConfig []byte) (any, error) { - return nil, nil -} - // BodyBuffer is an interface that provides access to the request and response body. // This should be implemented by the SDK or runtime. type BodyBuffer interface { @@ -456,6 +242,14 @@ type HttpFilterHandle interface { // SetFilterState sets the serialized filter state value of the stream. SetFilterState(key string, value []byte) + // SetFilterStateTyped sets the typed filter state value stored under the given key. The key + // MUST match a registered ObjectFactory; the bytes are passed to createFromBytes on that + // factory. This is the form required for interop with built-in Envoy filters that read filter + // state as typed objects (e.g., tcp_proxy reading PerConnectionCluster). + // Returns true on success, or false if no factory is registered for the key, the factory + // failed to create the object, or the key is read-only. + SetFilterStateTyped(key string, value []byte) bool + // GetAttributeString retrieves the string attribute value of the stream. // Returns attribute value if found, otherwise an empty UnsafeEnvoyBuffer. // NOTE: The memory of underlying data may not be managed by Go GC. So you should @@ -470,6 +264,14 @@ type HttpFilterHandle interface { // Returns attribute value and true if found, otherwise false. GetAttributeBool(attributeID AttributeID) (bool, bool) + // GetFilterStateTyped retrieves the serialized bytes of a typed filter state object stored + // under the given key. Unlike GetFilterState, this calls serializeAsString on the registered + // typed object, so it works for any filter state object type (not just StringAccessor). + // Returns serialized value if found, otherwise an empty UnsafeEnvoyBuffer and false. + // NOTE: The memory of the underlying data may not be managed by Go GC. Copy the data if you + // need to keep it past the current callback. + GetFilterStateTyped(key string) (UnsafeEnvoyBuffer, bool) + // GetData retrieves internal data stored for cross-phase communication. // This data is not included in DynamicMetadata responses. // Returns data value if found, otherwise nil. @@ -484,17 +286,14 @@ type HttpFilterHandle interface { // SendResponseHeaders sends response headers to the client. This is used for // streaming local replies. - // SendResponseHeaders(headers [][2]string, endOfStream bool) // SendResponseData sends response body data to the client. This is used for // streaming local replies. - // SendResponseData(body []byte, endOfStream bool) // SendResponseTrailers sends response trailers to the client. This is used for // streaming local replies. - // SendResponseTrailers(trailers [][2]string) // AddCustomFlag adds a custom flag to the stream. This flag should be very short @@ -520,46 +319,104 @@ type HttpFilterHandle interface { // cluster selection but not the route itself. RefreshRouteCluster() + // GetWorkerIndex returns the worker thread index assigned to the current HTTP filter. + // This can be used by the module to manage worker-specific resources. + GetWorkerIndex() uint32 + + // SetSocketOptionInt sets an integer-valued socket option on the upstream or downstream + // connection associated with the stream. Returns true on success. + SetSocketOptionInt(level, name int64, state SocketOptionState, direction SocketDirection, value int64) bool + + // SetSocketOptionBytes sets a bytes-valued socket option on the upstream or downstream + // connection associated with the stream. Returns true on success. + SetSocketOptionBytes(level, name int64, state SocketOptionState, direction SocketDirection, value []byte) bool + + // GetSocketOptionInt retrieves the integer value of a socket option. + // Returns value and true if found, otherwise 0 and false. + GetSocketOptionInt(level, name int64, state SocketOptionState, direction SocketDirection) (int64, bool) + + // GetSocketOptionBytes retrieves the bytes value of a socket option. The buffer is owned by + // Envoy and remains valid until the filter is destroyed. + // Returns value and true if found, otherwise an empty UnsafeEnvoyBuffer and false. + // NOTE: The memory of the underlying data may not be managed by Go GC. Copy the data if you + // need to keep it past the current callback. + GetSocketOptionBytes(level, name int64, state SocketOptionState, direction SocketDirection) (UnsafeEnvoyBuffer, bool) + + // GetBufferLimit returns the current per-stream body buffer limit in bytes. A limit of 0 + // indicates no limit is applied. + GetBufferLimit() uint64 + + // SetBufferLimit sets the per-stream body buffer limit. It is recommended (but not required) + // that filters only INCREASE the limit, to avoid conflicting with the buffer requirements of + // other filters in the chain. + SetBufferLimit(limit uint64) + + // GetActiveSpan returns the active tracing span for the stream, or nil if tracing is disabled + // or no span is available. The returned Span is owned by Envoy; do not Finish it. Use + // Span.SpawnChild to create module-owned child spans. + GetActiveSpan() Span + + // GetClusterName returns the name of the cluster the current request is routed to. + // Returns cluster name and true if found, otherwise an empty UnsafeEnvoyBuffer and false. + // NOTE: The memory of the underlying data may not be managed by Go GC. Copy the data if you + // need to keep it past the current callback. + GetClusterName() (UnsafeEnvoyBuffer, bool) + + // GetClusterHostCounts returns the host counts for the routed cluster at the given priority. + // Returns host counts and true if successful, otherwise a zero-valued struct and false. + GetClusterHostCounts(priority uint32) (ClusterHostCounts, bool) + + // SetUpstreamOverrideHost sets a host that the upstream load balancer should select first + // if it exists in the routed cluster. Useful for sticky sessions or host affinity. When + // strict is false, normal load balancing is used as a fallback. Returns false if the host + // address was invalid. + SetUpstreamOverrideHost(host string, strict bool) bool + + // ResetStream resets the HTTP stream with the given reason and optional details. After this + // call, no further filter callbacks will be invoked except OnDestroy. + ResetStream(reason HttpFilterStreamResetReason, details string) + + // SendGoAwayAndClose sends a GOAWAY frame to the downstream and closes the connection. If + // graceful is true, a graceful drain is initiated before closing. + SendGoAwayAndClose(graceful bool) + + // RecreateStream recreates the HTTP stream, optionally with new headers (or with the original + // headers if headers is nil). Useful for internal redirects or request retries. After a + // successful call, the current filter chain is destroyed and the filter SHOULD return Stop + // from the current callback. Returns false if recreation could not be initiated (e.g., the + // request body has not been fully received yet). + RecreateStream(headers [][2]string) bool + // RequestHeaders retrieves the request headers. - // Returns request headers. RequestHeaders() HeaderMap // BufferedRequestBody retrieves the buffered request body in the chain. - // NOTE: Different with the headers and trailers, because of the streaming processing, - // the request body is not always fully buffered. So this function only retrieves the - // currently buffered body in the chain. And the latest newly received body chunk is passed - // as the parameter to OnRequestBody. Only when endOfStream is true or OnRequestTrailers is - // called, the full request body is received. - // Returns buffered request body. + // NOTE: Because of streaming processing, the request body is not always fully buffered. + // This function only retrieves the currently buffered body in the chain. The latest newly + // received body chunk is passed as the parameter to OnRequestBody. Only when endOfStream is + // true or OnRequestTrailers is called is the full request body received. BufferedRequestBody() BodyBuffer - // ReceivedRequestBody retrieves the latest received request body chunk in the OnRequestBody callback. - // NOTE: This is only valid in the OnRequestBody callback, and it retrieves the latest received - // body chunk that triggers the callback. For other callbacks or outside of the callbacks, you - // should use BufferedRequestBody to get the currently buffered body in the chain. + // ReceivedRequestBody retrieves the latest received request body chunk in the OnRequestBody + // callback. + // NOTE: This is only valid in the OnRequestBody callback. For other callbacks or outside of + // callbacks, use BufferedRequestBody to get the currently buffered body in the chain. ReceivedRequestBody() BodyBuffer // RequestTrailers retrieves the request trailers. - // Returns request trailers. RequestTrailers() HeaderMap // ResponseHeaders retrieves the response headers. - // Returns response headers. ResponseHeaders() HeaderMap - // BufferedResponseBody retrieves the buffered response body in the chain. - // NOTE: Different with the headers and trailers, because of the streaming processing, - // the request body is not always fully buffered. So this function only retrieves the - // currently buffered body in the chain. And the latest newly received body chunk is passed - // as the parameter to OnResponseBody. Only when endOfStream is true or OnResponseTrailers is - // called, the full request body is received. - // Returns buffered response body. + // BufferedResponseBody retrieves the buffered response body in the chain. See + // BufferedRequestBody for the buffering caveats. BufferedResponseBody() BodyBuffer - // ReceivedResponseBody retrieves the latest received response body chunk in the OnResponseBody callback. - // NOTE: This is only valid in the OnResponseBody callback, and it retrieves the latest received - // body chunk that triggers the callback. For other callbacks or outside of the callbacks, you - // should use BufferedResponseBody to get the currently buffered body in the chain. + // ReceivedResponseBody retrieves the latest received response body chunk in the OnResponseBody + // callback. + // NOTE: This is only valid in the OnResponseBody callback. For other callbacks or outside of + // callbacks, use BufferedResponseBody to get the currently buffered body in the chain. ReceivedResponseBody() BodyBuffer // ReceivedBufferedRequestBody returns true if the latest received request body is the @@ -577,7 +434,6 @@ type HttpFilterHandle interface { ReceivedBufferedResponseBody() bool // ResponseTrailers retrieves the response trailers. - // Returns response trailers. ResponseTrailers() HeaderMap // GetMostSpecificConfig retrieves the most specific route configuration for the stream. @@ -594,55 +450,51 @@ type HttpFilterHandle interface { // Log will log the given message via the host environment's logging mechanism. Log(level LogLevel, format string, args ...any) - // HttpCallout performs an HTTP call to an external service. The call is asynchronous, and the - // response will be delivered via the provided callback. - // error occurs. - // The callback function receives the response headers, body, and an error if any occurred. + // HttpCallout performs an HTTP call to an external service. The call is asynchronous; the + // response, or an error, is delivered to the provided callback. // - // Returns result of the HTTP callout initialization and the callout ID. Non-success results - // indicate that the callout failed to start. + // Returns the initialization result and the callout ID. A non-success result indicates the + // callout failed to start. // // NOTE: This method should only be called during OnRequest* or OnResponse* callbacks or - // scheduled functions via the Scheduler. By this way we can ensure this is only be called - // in the thread where the stream plugin is being processed. + // from a scheduled function, so that it runs on the thread where the stream is being + // processed. HttpCallout(cluster string, headers [][2]string, body []byte, timeoutMs uint64, cb HttpCalloutCallback) (HttpCalloutInitResult, uint64) - // StartHttpStream starts a new HTTP stream to an external service. The stream is asynchronous, - // and the response will be delivered via the provided callback. + // StartHttpStream starts a new HTTP stream to an external service. The stream is asynchronous; + // responses are delivered to the provided callback. // - // Returns result of the HTTP stream initialization and the stream ID. Non-success results - // indicate that the stream failed to start. + // Returns the initialization result and the stream ID. A non-success result indicates the + // stream failed to start. // // NOTE: This method should only be called during OnRequest* or OnResponse* callbacks or - // scheduled functions via the Scheduler. By this way we can ensure this is only be called - // in the thread where the stream plugin is being processed. + // from a scheduled function, so that it runs on the thread where the stream is being + // processed. StartHttpStream(cluster string, headers [][2]string, body []byte, endOfStream bool, timeoutMs uint64, cb HttpStreamCallback) (HttpCalloutInitResult, uint64) - // SendHttpStreamData sends data on an existing HTTP stream. - // - // Returns the data was successfully sent. + // SendHttpStreamData sends data on an existing HTTP stream. Returns true if the data was + // sent successfully. // // NOTE: This method should only be called during OnRequest* or OnResponse* callbacks or - // scheduled functions via the Scheduler. By this way we can ensure this is only be called - // in the thread where the stream plugin is being processed. + // from a scheduled function, so that it runs on the thread where the stream is being + // processed. SendHttpStreamData(streamID uint64, body []byte, endOfStream bool) bool - // SendHttpStreamTrailers sends trailers on an existing HTTP stream. - // - // Returns the trailers were successfully sent. + // SendHttpStreamTrailers sends trailers on an existing HTTP stream. Returns true if the + // trailers were sent successfully. // // NOTE: This method should only be called during OnRequest* or OnResponse* callbacks or - // scheduled functions via the Scheduler. By this way we can ensure this is only be called - // in the thread where the stream plugin is being processed. + // from a scheduled function, so that it runs on the thread where the stream is being + // processed. SendHttpStreamTrailers(streamID uint64, trailers [][2]string) bool // ResetHttpStream resets an existing HTTP stream. // // NOTE: This method should only be called during OnRequest* or OnResponse* callbacks or - // scheduled functions via the Scheduler. By this way we can ensure this is only be called - // in the thread where the stream plugin is being processed. + // from a scheduled function, so that it runs on the thread where the stream is being + // processed. ResetHttpStream(streamID uint64) // SetDownstreamWatermarkCallbacks sets the downstream watermark callbacks for the stream. @@ -651,113 +503,25 @@ type HttpFilterHandle interface { // ClearDownstreamWatermarkCallbacks unsets the downstream watermark callbacks for the stream. ClearDownstreamWatermarkCallbacks() - // RecordValue records the given value to the histogram metric. - // of the tag values must match the tag keys defined when the metric was created. + // RecordHistogramValue records the given value to the histogram metric. The order and + // size of tagsValues must match the tag keys defined when the metric was created. RecordHistogramValue(id MetricID, value uint64, tagsValues ...string) MetricsResult - // SetValue sets the given value to the gauge metric. - // of the tag values must match the tag keys defined when the metric was created. + // SetGaugeValue sets the given value on the gauge metric. The order and size of + // tagsValues must match the tag keys defined when the metric was created. SetGaugeValue(id MetricID, value uint64, tagsValues ...string) MetricsResult - // IncrementGaugeValue adds the given value to the gauge metric. - // of the tag values must match the tag keys defined when the metric was created. + // IncrementGaugeValue adds the given value to the gauge metric. The order and size of + // tagsValues must match the tag keys defined when the metric was created. IncrementGaugeValue(id MetricID, value uint64, tagsValues ...string) MetricsResult - // DecrementGaugeValue subtracts the given value from the gauge metric. - // of the tag values must match the tag keys defined when the metric was created. + // DecrementGaugeValue subtracts the given value from the gauge metric. The order and + // size of tagsValues must match the tag keys defined when the metric was created. DecrementGaugeValue(id MetricID, value uint64, tagsValues ...string) MetricsResult - // IncrementCounterValue adds the given value to the counter metric. - // of the tag values must match the tag keys defined when the metric was created. + // IncrementCounterValue adds the given value to the counter metric. The order and + // size of tagsValues must match the tag keys defined when the metric was created. IncrementCounterValue(id MetricID, value uint64, tagsValues ...string) MetricsResult - - // GetWorkerIndex returns the worker thread index assigned to the current HTTP filter. - // This can be used by the module to manage worker-specific resources. - GetWorkerIndex() uint32 - - // GetFilterStateTyped retrieves the serialized bytes of a typed filter state object stored - // under the given key. Unlike GetFilterState, this calls serializeAsString on the registered - // typed object, so it works for any filter state object type (not just StringAccessor). - // Returns serialized value if found, otherwise an empty UnsafeEnvoyBuffer and false. - // NOTE: The memory of the underlying data may not be managed by Go GC. Copy the data if you - // need to keep it past the current callback. - GetFilterStateTyped(key string) (UnsafeEnvoyBuffer, bool) - - // SetFilterStateTyped sets the typed filter state value stored under the given key. The key - // MUST match a registered ObjectFactory; the bytes are passed to createFromBytes on that - // factory. This is the form required for interop with built-in Envoy filters that read filter - // state as typed objects (e.g., tcp_proxy reading PerConnectionCluster). - // Returns if the operation was successful, false otherwise (e.g., no factory registered - // for the key, factory failed to create the object, or the key is read-only). - SetFilterStateTyped(key string, value []byte) bool - - // SetSocketOptionInt sets an integer-valued socket option on the upstream or downstream - // connection associated with the stream. - // downstream sockets. - // Returns if the operation was successful, false otherwise. - SetSocketOptionInt(level, name int64, state SocketOptionState, direction SocketDirection, value int64) bool - - // SetSocketOptionBytes sets a bytes-valued socket option on the upstream or downstream - // connection associated with the stream. - // Returns if the operation was successful, false otherwise. - SetSocketOptionBytes(level, name int64, state SocketOptionState, direction SocketDirection, value []byte) bool - - // GetSocketOptionInt retrieves the integer value of a socket option. - // Returns value and true if found, otherwise 0 and false. - GetSocketOptionInt(level, name int64, state SocketOptionState, direction SocketDirection) (int64, bool) - - // GetSocketOptionBytes retrieves the bytes value of a socket option. The buffer is owned by - // Envoy and remains valid until the filter is destroyed. - // Returns value and true if found, otherwise an empty UnsafeEnvoyBuffer and false. - // NOTE: The memory of the underlying data may not be managed by Go GC. Copy the data if you - // need to keep it past the current callback. - GetSocketOptionBytes(level, name int64, state SocketOptionState, direction SocketDirection) (UnsafeEnvoyBuffer, bool) - - // GetBufferLimit returns the current per-stream body buffer limit in bytes. A limit of 0 - // indicates no limit is applied. - GetBufferLimit() uint64 - - // SetBufferLimit sets the per-stream body buffer limit. It is recommended (but not required) - // that filters only INCREASE the limit, to avoid conflicting with the buffer requirements of - // other filters in the chain. - SetBufferLimit(limit uint64) - - // GetActiveSpan returns the active tracing span for the stream, or nil if tracing is disabled - // or no span is available. The returned Span is owned by Envoy; do not Finish it. Use - // Span.SpawnChild to create module-owned child spans. - GetActiveSpan() Span - - // GetClusterName returns the name of the cluster the current request is routed to. - // Returns cluster name and true if found, otherwise an empty UnsafeEnvoyBuffer and false. - // NOTE: The memory of the underlying data may not be managed by Go GC. Copy the data if you - // need to keep it past the current callback. - GetClusterName() (UnsafeEnvoyBuffer, bool) - - // GetClusterHostCounts returns the host counts for the routed cluster at the given priority. - // Returns host counts and true if successful, otherwise a zero-valued struct and false. - GetClusterHostCounts(priority uint32) (ClusterHostCounts, bool) - - // SetUpstreamOverrideHost sets a host that the upstream load balancer should select first if - // it exists in the routed cluster. This is useful for sticky sessions or host affinity. - // false, normal load balancing is used as a fallback. - // Returns if the override was set successfully, false if the host address was invalid. - SetUpstreamOverrideHost(host string, strict bool) bool - - // ResetStream resets the HTTP stream with the given reason and optional details. After this - // call, no further filter callbacks will be invoked except OnDestroy. - ResetStream(reason HttpFilterStreamResetReason, details string) - - // SendGoAwayAndClose sends a GOAWAY frame to the downstream and closes the connection. If - // graceful is true, a graceful drain is initiated before closing. - SendGoAwayAndClose(graceful bool) - - // RecreateStream recreates the HTTP stream, optionally with new headers (or with the original - // headers if headers is nil). Useful for internal redirects or request retries. After a - // successful call, the current filter chain is destroyed and the filter SHOULD return Stop - // from the current callback. - // Returns if recreation was initiated, false otherwise (e.g., the request body has not - // been fully received yet). - RecreateStream(headers [][2]string) bool } // HttpFilterConfigHandle is the per-filter-config handle exposed to HttpFilterConfig @@ -798,11 +562,11 @@ type HttpFilterConfigHandle interface { timeoutMs uint64, cb HttpStreamCallback) (HttpCalloutInitResult, uint64) // SendHttpStreamData sends data on an existing HTTP stream started via StartHttpStream. - // Returns the data was successfully sent. + // Returns true if the data was sent successfully. SendHttpStreamData(streamID uint64, body []byte, endOfStream bool) bool // SendHttpStreamTrailers sends trailers on an existing HTTP stream started via StartHttpStream. - // Returns the trailers were successfully sent. + // Returns true if the trailers were sent successfully. SendHttpStreamTrailers(streamID uint64, trailers [][2]string) bool // ResetHttpStream resets an existing HTTP stream started via StartHttpStream. diff --git a/source/extensions/dynamic_modules/sdk/go/shared/http_api.go b/source/extensions/dynamic_modules/sdk/go/shared/http_api.go new file mode 100644 index 0000000000000..d18f8a31db6b3 --- /dev/null +++ b/source/extensions/dynamic_modules/sdk/go/shared/http_api.go @@ -0,0 +1,217 @@ +//go:generate mockgen -source=http_api.go -destination=mocks/mock_http_api.go -package=mocks +package shared + +type HeadersStatus int32 + +const ( + // '2' is preserved for ContinueAndDontEndStream and is not exposed here. + + // HeadersStatusContinue indicates that the headers can continue to be processed by + // next plugin in the chain and nothing will be stopped. + HeadersStatusContinue HeadersStatus = 0 + // HeadersStatusStop indicates that the headers processing should stop at this plugin. + // And when the body or trailers are received, the onRequestBody or onRequestTrailers + // of this plugin will be called. And the filter chain will continue or still hang + // based on the returned status of onRequestBody or onRequestTrailers. + // Of course the continueRequestStream or continueResponseStream can be called to continue + // the processing manually. + HeadersStatusStop HeadersStatus = 1 + // HeadersStatusStopAndBuffer indicates that the headers processing should stop at this plugin. + // And even if the body or trailers are received, the onRequestBody or onRequestTrailers + // of this plugin will NOT be called and the body will be buffered. The only way to continue + // the processing is to call continueRequestStream or continueResponseStream manually. + // This is useful when you want to wait a certain condition to be met before continuing + // the processing (For example, waiting for the result of an asynchronous operation). + HeadersStatusStopAllAndBuffer HeadersStatus = 3 + // Similar to HeadersStatusStopAllAndBuffer. But when there are too big body data buffered, + // the HeadersStatusStopAllAndBuffer will result in 413 (Payload Too Large) response to the + // client. But with this status, the watermarking will be used to disable reading from client + // or server. + HeadersStatusStopAllAndWatermark HeadersStatus = 4 + HeadersStatusDefault HeadersStatus = HeadersStatusContinue +) + +type BodyStatus int32 + +const ( + // BodyStatusContinue indicates that the body can continue to be processed by next plugin + // in the chain. And if the onRequestHeaders or onResponseHeaders of this plugin returned + // HeadersStatusStop before, the headers processing will continue. + BodyStatusContinue BodyStatus = 0 + // BodyStatusStopAndBuffer indicates that the body processing should stop at this plugin. + // And the body will be buffered. + BodyStatusStopAndBuffer BodyStatus = 1 + // BodyStatusStopAndWatermark indicates that the body processing should stop at this plugin. + // And watermarking will be used to disable reading from client or server if there are too + // big body data buffered. + BodyStatusStopAndWatermark BodyStatus = 2 + // BodyStatusStopNoBuffer indicates that the body processing should stop at this plugin. + // No body data will be buffered. + BodyStatusStopNoBuffer BodyStatus = 3 + BodyStatusDefault BodyStatus = BodyStatusContinue +) + +type TrailersStatus int32 + +const ( + // TrailersStatusContinue indicates that the trailers can continue to be processed by next plugin + // in the chain. And if the onRequestHeaders, onResponseHeaders, onRequestBody or onResponseBody + // of this plugin have returned stop status before, the processing will continue after this. + TrailersStatusContinue TrailersStatus = 0 + // TrailersStatusStop indicates that the trailers processing should stop at this plugin. The + // only way to continue the processing is to call continueRequestStream or continueResponseStream + // manually. + TrailersStatusStop TrailersStatus = 1 + TrailersStatusDefault TrailersStatus = TrailersStatusContinue +) + +// LocalReplyStatus is returned from HttpFilter.OnLocalReply to control whether Envoy should +// send the local reply to the client or reset the stream instead. +type LocalReplyStatus int32 + +const ( + // LocalReplyStatusContinue indicates that the local reply should continue to be sent + // after all filters are informed. + LocalReplyStatusContinue LocalReplyStatus = 0 + // LocalReplyStatusContinueAndResetStream indicates that the local reply notification + // should continue to all filters, but the stream should be reset instead of sending + // the local reply. + LocalReplyStatusContinueAndResetStream LocalReplyStatus = 1 + LocalReplyStatusDefault LocalReplyStatus = LocalReplyStatusContinue +) + +// HttpFilter is the interface to implement your own plugin logic. This is a simplified version and could +// not implement flexible stream control. But it should be enough for most of the use cases. +type HttpFilter interface { + // OnRequestHeaders will be called when the request headers are received. + // Returns the status to control the plugin chain processing. + OnRequestHeaders(headers HeaderMap, endOfStream bool) HeadersStatus + + // OnRequestBody will be called when the request body are received. This may be called multiple times. + // Returns the status to control the plugin chain processing. + OnRequestBody(body BodyBuffer, endOfStream bool) BodyStatus + + // OnRequestTrailers will be called when the request trailers are received. + // Returns the status to control the plugin chain processing. + OnRequestTrailers(trailers HeaderMap) TrailersStatus + + // OnResponseHeaders will be called when the response headers are received. + // Returns the status to control the plugin chain processing. + OnResponseHeaders(headers HeaderMap, endOfStream bool) HeadersStatus + + // OnResponseBody will be called when the response body is received. This may be called multiple + // times. + // Returns the status to control the plugin chain processing. + OnResponseBody(body BodyBuffer, endOfStream bool) BodyStatus + + // OnResponseTrailers will be called when the response trailers are received. + // Returns the status to control the plugin chain processing. + OnResponseTrailers(trailers HeaderMap) TrailersStatus + + // OnStreamComplete is called when the stream processing is complete and before access logs + // are flushed. + // This is a good place to do any final processing or cleanup before the request is fully + // completed. + OnStreamComplete() + + // OnDestroy is called when the HTTP filter instance is being destroyed. This is called + // after OnStreamComplete and access logs are flushed. This is a good place to release + // any per-stream resources. + OnDestroy() + + // OnLocalReply is called when a local reply is being sent. The filter can either let the + // reply proceed (LocalReplyStatusContinue) or ask Envoy to reset the stream instead + // (LocalReplyStatusContinueAndResetStream). This is invoked before the reply leaves + // Envoy and before any stream reset. + // + // details is a short description of why the local reply is being sent (e.g. + // "buffer overflow", "rate limit exceeded"). The buffer aliases Envoy memory; copy + // before retaining past this call. resetImminent is true if Envoy is going to reset + // the stream after this call. + OnLocalReply(responseCode uint32, details UnsafeEnvoyBuffer, resetImminent bool) LocalReplyStatus +} + +type EmptyHttpFilter struct { +} + +func (p *EmptyHttpFilter) OnRequestHeaders(headers HeaderMap, endOfStream bool) HeadersStatus { + return HeadersStatusDefault +} + +func (p *EmptyHttpFilter) OnRequestBody(body BodyBuffer, endOfStream bool) BodyStatus { + return BodyStatusDefault +} + +func (p *EmptyHttpFilter) OnRequestTrailers(trailers HeaderMap) TrailersStatus { + return TrailersStatusDefault +} + +func (p *EmptyHttpFilter) OnResponseHeaders(headers HeaderMap, endOfStream bool) HeadersStatus { + return HeadersStatusDefault +} + +func (p *EmptyHttpFilter) OnResponseBody(body BodyBuffer, endOfStream bool) BodyStatus { + return BodyStatusDefault +} + +func (p *EmptyHttpFilter) OnResponseTrailers(trailers HeaderMap) TrailersStatus { + return TrailersStatusDefault +} + +func (p *EmptyHttpFilter) OnStreamComplete() { +} + +func (p *EmptyHttpFilter) OnDestroy() { +} + +func (p *EmptyHttpFilter) OnLocalReply(responseCode uint32, details UnsafeEnvoyBuffer, resetImminent bool) LocalReplyStatus { + return LocalReplyStatusDefault +} + +// HttpFilterFactory is the factory interface for creating stream plugins. +// This is used to create instances of the stream plugin at runtime when a new request is received. +// The implementation of this interface should be thread-safe and hold the parsed configuration. +type HttpFilterFactory interface { + // Create creates a HttpFilter instance. + Create(handle HttpFilterHandle) HttpFilter + + // OnDestroy is called when the factory is being destroyed. This is a good place to clean up any + // resources. This usually happens when the configuration is updated and all existing streams + // using this factory are closed. + OnDestroy() +} + +type EmptyHttpFilterFactory struct { +} + +func (f *EmptyHttpFilterFactory) Create(handle HttpFilterHandle) HttpFilter { + return &EmptyHttpFilter{} +} + +func (f *EmptyHttpFilterFactory) OnDestroy() { +} + +// HttpFilterConfigFactory is the factory interface for creating stream plugin configurations. +// This is used to create +// PluginConfig based on the unparsed configuration. The HttpFilterConfigFactory should parse the unparsedConfig +// and create a PluginFactory instance. +// The implementation of this interface should be thread-safe and be stateless in most cases. +type HttpFilterConfigFactory interface { + // Create creates a HttpFilterFactory based on the unparsed configuration. + Create(handle HttpFilterConfigHandle, unparsedConfig []byte) (HttpFilterFactory, error) + + // CreatePerRoute creates a per-route configuration based on the unparsed configuration. + CreatePerRoute(unparsedConfig []byte) (any, error) +} + +type EmptyHttpFilterConfigFactory struct { +} + +func (f *EmptyHttpFilterConfigFactory) Create(handle HttpFilterConfigHandle, + unparsedConfig []byte) (HttpFilterFactory, error) { + return &EmptyHttpFilterFactory{}, nil +} + +func (f *EmptyHttpFilterConfigFactory) CreatePerRoute(unparsedConfig []byte) (any, error) { + return nil, nil +} diff --git a/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_http.go b/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_http.go index e3b7aa96e9b9c..7e2a6a8b981cd 100644 --- a/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_http.go +++ b/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_http.go @@ -16,256 +16,6 @@ import ( gomock "go.uber.org/mock/gomock" ) -// MockHttpFilter is a mock of HttpFilter interface. -type MockHttpFilter struct { - ctrl *gomock.Controller - recorder *MockHttpFilterMockRecorder - isgomock struct{} -} - -// MockHttpFilterMockRecorder is the mock recorder for MockHttpFilter. -type MockHttpFilterMockRecorder struct { - mock *MockHttpFilter -} - -// NewMockHttpFilter creates a new mock instance. -func NewMockHttpFilter(ctrl *gomock.Controller) *MockHttpFilter { - mock := &MockHttpFilter{ctrl: ctrl} - mock.recorder = &MockHttpFilterMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockHttpFilter) EXPECT() *MockHttpFilterMockRecorder { - return m.recorder -} - -// OnDestroy mocks base method. -func (m *MockHttpFilter) OnDestroy() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "OnDestroy") -} - -// OnDestroy indicates an expected call of OnDestroy. -func (mr *MockHttpFilterMockRecorder) OnDestroy() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnDestroy", reflect.TypeOf((*MockHttpFilter)(nil).OnDestroy)) -} - -// OnLocalReply mocks base method. -func (m *MockHttpFilter) OnLocalReply(responseCode uint32, details shared.UnsafeEnvoyBuffer, resetImminent bool) shared.LocalReplyStatus { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnLocalReply", responseCode, details, resetImminent) - ret0, _ := ret[0].(shared.LocalReplyStatus) - return ret0 -} - -// OnLocalReply indicates an expected call of OnLocalReply. -func (mr *MockHttpFilterMockRecorder) OnLocalReply(responseCode, details, resetImminent any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnLocalReply", reflect.TypeOf((*MockHttpFilter)(nil).OnLocalReply), responseCode, details, resetImminent) -} - -// OnRequestBody mocks base method. -func (m *MockHttpFilter) OnRequestBody(body shared.BodyBuffer, endOfStream bool) shared.BodyStatus { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnRequestBody", body, endOfStream) - ret0, _ := ret[0].(shared.BodyStatus) - return ret0 -} - -// OnRequestBody indicates an expected call of OnRequestBody. -func (mr *MockHttpFilterMockRecorder) OnRequestBody(body, endOfStream any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnRequestBody", reflect.TypeOf((*MockHttpFilter)(nil).OnRequestBody), body, endOfStream) -} - -// OnRequestHeaders mocks base method. -func (m *MockHttpFilter) OnRequestHeaders(headers shared.HeaderMap, endOfStream bool) shared.HeadersStatus { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnRequestHeaders", headers, endOfStream) - ret0, _ := ret[0].(shared.HeadersStatus) - return ret0 -} - -// OnRequestHeaders indicates an expected call of OnRequestHeaders. -func (mr *MockHttpFilterMockRecorder) OnRequestHeaders(headers, endOfStream any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnRequestHeaders", reflect.TypeOf((*MockHttpFilter)(nil).OnRequestHeaders), headers, endOfStream) -} - -// OnRequestTrailers mocks base method. -func (m *MockHttpFilter) OnRequestTrailers(trailers shared.HeaderMap) shared.TrailersStatus { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnRequestTrailers", trailers) - ret0, _ := ret[0].(shared.TrailersStatus) - return ret0 -} - -// OnRequestTrailers indicates an expected call of OnRequestTrailers. -func (mr *MockHttpFilterMockRecorder) OnRequestTrailers(trailers any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnRequestTrailers", reflect.TypeOf((*MockHttpFilter)(nil).OnRequestTrailers), trailers) -} - -// OnResponseBody mocks base method. -func (m *MockHttpFilter) OnResponseBody(body shared.BodyBuffer, endOfStream bool) shared.BodyStatus { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnResponseBody", body, endOfStream) - ret0, _ := ret[0].(shared.BodyStatus) - return ret0 -} - -// OnResponseBody indicates an expected call of OnResponseBody. -func (mr *MockHttpFilterMockRecorder) OnResponseBody(body, endOfStream any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnResponseBody", reflect.TypeOf((*MockHttpFilter)(nil).OnResponseBody), body, endOfStream) -} - -// OnResponseHeaders mocks base method. -func (m *MockHttpFilter) OnResponseHeaders(headers shared.HeaderMap, endOfStream bool) shared.HeadersStatus { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnResponseHeaders", headers, endOfStream) - ret0, _ := ret[0].(shared.HeadersStatus) - return ret0 -} - -// OnResponseHeaders indicates an expected call of OnResponseHeaders. -func (mr *MockHttpFilterMockRecorder) OnResponseHeaders(headers, endOfStream any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnResponseHeaders", reflect.TypeOf((*MockHttpFilter)(nil).OnResponseHeaders), headers, endOfStream) -} - -// OnResponseTrailers mocks base method. -func (m *MockHttpFilter) OnResponseTrailers(trailers shared.HeaderMap) shared.TrailersStatus { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnResponseTrailers", trailers) - ret0, _ := ret[0].(shared.TrailersStatus) - return ret0 -} - -// OnResponseTrailers indicates an expected call of OnResponseTrailers. -func (mr *MockHttpFilterMockRecorder) OnResponseTrailers(trailers any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnResponseTrailers", reflect.TypeOf((*MockHttpFilter)(nil).OnResponseTrailers), trailers) -} - -// OnStreamComplete mocks base method. -func (m *MockHttpFilter) OnStreamComplete() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "OnStreamComplete") -} - -// OnStreamComplete indicates an expected call of OnStreamComplete. -func (mr *MockHttpFilterMockRecorder) OnStreamComplete() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnStreamComplete", reflect.TypeOf((*MockHttpFilter)(nil).OnStreamComplete)) -} - -// MockHttpFilterFactory is a mock of HttpFilterFactory interface. -type MockHttpFilterFactory struct { - ctrl *gomock.Controller - recorder *MockHttpFilterFactoryMockRecorder - isgomock struct{} -} - -// MockHttpFilterFactoryMockRecorder is the mock recorder for MockHttpFilterFactory. -type MockHttpFilterFactoryMockRecorder struct { - mock *MockHttpFilterFactory -} - -// NewMockHttpFilterFactory creates a new mock instance. -func NewMockHttpFilterFactory(ctrl *gomock.Controller) *MockHttpFilterFactory { - mock := &MockHttpFilterFactory{ctrl: ctrl} - mock.recorder = &MockHttpFilterFactoryMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockHttpFilterFactory) EXPECT() *MockHttpFilterFactoryMockRecorder { - return m.recorder -} - -// Create mocks base method. -func (m *MockHttpFilterFactory) Create(handle shared.HttpFilterHandle) shared.HttpFilter { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Create", handle) - ret0, _ := ret[0].(shared.HttpFilter) - return ret0 -} - -// Create indicates an expected call of Create. -func (mr *MockHttpFilterFactoryMockRecorder) Create(handle any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockHttpFilterFactory)(nil).Create), handle) -} - -// OnDestroy mocks base method. -func (m *MockHttpFilterFactory) OnDestroy() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "OnDestroy") -} - -// OnDestroy indicates an expected call of OnDestroy. -func (mr *MockHttpFilterFactoryMockRecorder) OnDestroy() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnDestroy", reflect.TypeOf((*MockHttpFilterFactory)(nil).OnDestroy)) -} - -// MockHttpFilterConfigFactory is a mock of HttpFilterConfigFactory interface. -type MockHttpFilterConfigFactory struct { - ctrl *gomock.Controller - recorder *MockHttpFilterConfigFactoryMockRecorder - isgomock struct{} -} - -// MockHttpFilterConfigFactoryMockRecorder is the mock recorder for MockHttpFilterConfigFactory. -type MockHttpFilterConfigFactoryMockRecorder struct { - mock *MockHttpFilterConfigFactory -} - -// NewMockHttpFilterConfigFactory creates a new mock instance. -func NewMockHttpFilterConfigFactory(ctrl *gomock.Controller) *MockHttpFilterConfigFactory { - mock := &MockHttpFilterConfigFactory{ctrl: ctrl} - mock.recorder = &MockHttpFilterConfigFactoryMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockHttpFilterConfigFactory) EXPECT() *MockHttpFilterConfigFactoryMockRecorder { - return m.recorder -} - -// Create mocks base method. -func (m *MockHttpFilterConfigFactory) Create(handle shared.HttpFilterConfigHandle, unparsedConfig []byte) (shared.HttpFilterFactory, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Create", handle, unparsedConfig) - ret0, _ := ret[0].(shared.HttpFilterFactory) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Create indicates an expected call of Create. -func (mr *MockHttpFilterConfigFactoryMockRecorder) Create(handle, unparsedConfig any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockHttpFilterConfigFactory)(nil).Create), handle, unparsedConfig) -} - -// CreatePerRoute mocks base method. -func (m *MockHttpFilterConfigFactory) CreatePerRoute(unparsedConfig []byte) (any, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreatePerRoute", unparsedConfig) - ret0, _ := ret[0].(any) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CreatePerRoute indicates an expected call of CreatePerRoute. -func (mr *MockHttpFilterConfigFactoryMockRecorder) CreatePerRoute(unparsedConfig any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreatePerRoute", reflect.TypeOf((*MockHttpFilterConfigFactory)(nil).CreatePerRoute), unparsedConfig) -} - // MockBodyBuffer is a mock of BodyBuffer interface. type MockBodyBuffer struct { ctrl *gomock.Controller diff --git a/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_http_api.go b/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_http_api.go new file mode 100644 index 0000000000000..2a53851cbeadd --- /dev/null +++ b/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_http_api.go @@ -0,0 +1,267 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: http_api.go +// +// Generated by this command: +// +// mockgen -source=http_api.go -destination=mocks/mock_http_api.go -package=mocks +// + +// Package mocks is a generated GoMock package. +package mocks + +import ( + reflect "reflect" + + shared "github.com/envoyproxy/envoy/source/extensions/dynamic_modules/sdk/go/shared" + gomock "go.uber.org/mock/gomock" +) + +// MockHttpFilter is a mock of HttpFilter interface. +type MockHttpFilter struct { + ctrl *gomock.Controller + recorder *MockHttpFilterMockRecorder + isgomock struct{} +} + +// MockHttpFilterMockRecorder is the mock recorder for MockHttpFilter. +type MockHttpFilterMockRecorder struct { + mock *MockHttpFilter +} + +// NewMockHttpFilter creates a new mock instance. +func NewMockHttpFilter(ctrl *gomock.Controller) *MockHttpFilter { + mock := &MockHttpFilter{ctrl: ctrl} + mock.recorder = &MockHttpFilterMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockHttpFilter) EXPECT() *MockHttpFilterMockRecorder { + return m.recorder +} + +// OnDestroy mocks base method. +func (m *MockHttpFilter) OnDestroy() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OnDestroy") +} + +// OnDestroy indicates an expected call of OnDestroy. +func (mr *MockHttpFilterMockRecorder) OnDestroy() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnDestroy", reflect.TypeOf((*MockHttpFilter)(nil).OnDestroy)) +} + +// OnLocalReply mocks base method. +func (m *MockHttpFilter) OnLocalReply(responseCode uint32, details shared.UnsafeEnvoyBuffer, resetImminent bool) shared.LocalReplyStatus { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnLocalReply", responseCode, details, resetImminent) + ret0, _ := ret[0].(shared.LocalReplyStatus) + return ret0 +} + +// OnLocalReply indicates an expected call of OnLocalReply. +func (mr *MockHttpFilterMockRecorder) OnLocalReply(responseCode, details, resetImminent any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnLocalReply", reflect.TypeOf((*MockHttpFilter)(nil).OnLocalReply), responseCode, details, resetImminent) +} + +// OnRequestBody mocks base method. +func (m *MockHttpFilter) OnRequestBody(body shared.BodyBuffer, endOfStream bool) shared.BodyStatus { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnRequestBody", body, endOfStream) + ret0, _ := ret[0].(shared.BodyStatus) + return ret0 +} + +// OnRequestBody indicates an expected call of OnRequestBody. +func (mr *MockHttpFilterMockRecorder) OnRequestBody(body, endOfStream any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnRequestBody", reflect.TypeOf((*MockHttpFilter)(nil).OnRequestBody), body, endOfStream) +} + +// OnRequestHeaders mocks base method. +func (m *MockHttpFilter) OnRequestHeaders(headers shared.HeaderMap, endOfStream bool) shared.HeadersStatus { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnRequestHeaders", headers, endOfStream) + ret0, _ := ret[0].(shared.HeadersStatus) + return ret0 +} + +// OnRequestHeaders indicates an expected call of OnRequestHeaders. +func (mr *MockHttpFilterMockRecorder) OnRequestHeaders(headers, endOfStream any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnRequestHeaders", reflect.TypeOf((*MockHttpFilter)(nil).OnRequestHeaders), headers, endOfStream) +} + +// OnRequestTrailers mocks base method. +func (m *MockHttpFilter) OnRequestTrailers(trailers shared.HeaderMap) shared.TrailersStatus { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnRequestTrailers", trailers) + ret0, _ := ret[0].(shared.TrailersStatus) + return ret0 +} + +// OnRequestTrailers indicates an expected call of OnRequestTrailers. +func (mr *MockHttpFilterMockRecorder) OnRequestTrailers(trailers any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnRequestTrailers", reflect.TypeOf((*MockHttpFilter)(nil).OnRequestTrailers), trailers) +} + +// OnResponseBody mocks base method. +func (m *MockHttpFilter) OnResponseBody(body shared.BodyBuffer, endOfStream bool) shared.BodyStatus { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnResponseBody", body, endOfStream) + ret0, _ := ret[0].(shared.BodyStatus) + return ret0 +} + +// OnResponseBody indicates an expected call of OnResponseBody. +func (mr *MockHttpFilterMockRecorder) OnResponseBody(body, endOfStream any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnResponseBody", reflect.TypeOf((*MockHttpFilter)(nil).OnResponseBody), body, endOfStream) +} + +// OnResponseHeaders mocks base method. +func (m *MockHttpFilter) OnResponseHeaders(headers shared.HeaderMap, endOfStream bool) shared.HeadersStatus { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnResponseHeaders", headers, endOfStream) + ret0, _ := ret[0].(shared.HeadersStatus) + return ret0 +} + +// OnResponseHeaders indicates an expected call of OnResponseHeaders. +func (mr *MockHttpFilterMockRecorder) OnResponseHeaders(headers, endOfStream any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnResponseHeaders", reflect.TypeOf((*MockHttpFilter)(nil).OnResponseHeaders), headers, endOfStream) +} + +// OnResponseTrailers mocks base method. +func (m *MockHttpFilter) OnResponseTrailers(trailers shared.HeaderMap) shared.TrailersStatus { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnResponseTrailers", trailers) + ret0, _ := ret[0].(shared.TrailersStatus) + return ret0 +} + +// OnResponseTrailers indicates an expected call of OnResponseTrailers. +func (mr *MockHttpFilterMockRecorder) OnResponseTrailers(trailers any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnResponseTrailers", reflect.TypeOf((*MockHttpFilter)(nil).OnResponseTrailers), trailers) +} + +// OnStreamComplete mocks base method. +func (m *MockHttpFilter) OnStreamComplete() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OnStreamComplete") +} + +// OnStreamComplete indicates an expected call of OnStreamComplete. +func (mr *MockHttpFilterMockRecorder) OnStreamComplete() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnStreamComplete", reflect.TypeOf((*MockHttpFilter)(nil).OnStreamComplete)) +} + +// MockHttpFilterFactory is a mock of HttpFilterFactory interface. +type MockHttpFilterFactory struct { + ctrl *gomock.Controller + recorder *MockHttpFilterFactoryMockRecorder + isgomock struct{} +} + +// MockHttpFilterFactoryMockRecorder is the mock recorder for MockHttpFilterFactory. +type MockHttpFilterFactoryMockRecorder struct { + mock *MockHttpFilterFactory +} + +// NewMockHttpFilterFactory creates a new mock instance. +func NewMockHttpFilterFactory(ctrl *gomock.Controller) *MockHttpFilterFactory { + mock := &MockHttpFilterFactory{ctrl: ctrl} + mock.recorder = &MockHttpFilterFactoryMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockHttpFilterFactory) EXPECT() *MockHttpFilterFactoryMockRecorder { + return m.recorder +} + +// Create mocks base method. +func (m *MockHttpFilterFactory) Create(handle shared.HttpFilterHandle) shared.HttpFilter { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Create", handle) + ret0, _ := ret[0].(shared.HttpFilter) + return ret0 +} + +// Create indicates an expected call of Create. +func (mr *MockHttpFilterFactoryMockRecorder) Create(handle any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockHttpFilterFactory)(nil).Create), handle) +} + +// OnDestroy mocks base method. +func (m *MockHttpFilterFactory) OnDestroy() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OnDestroy") +} + +// OnDestroy indicates an expected call of OnDestroy. +func (mr *MockHttpFilterFactoryMockRecorder) OnDestroy() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnDestroy", reflect.TypeOf((*MockHttpFilterFactory)(nil).OnDestroy)) +} + +// MockHttpFilterConfigFactory is a mock of HttpFilterConfigFactory interface. +type MockHttpFilterConfigFactory struct { + ctrl *gomock.Controller + recorder *MockHttpFilterConfigFactoryMockRecorder + isgomock struct{} +} + +// MockHttpFilterConfigFactoryMockRecorder is the mock recorder for MockHttpFilterConfigFactory. +type MockHttpFilterConfigFactoryMockRecorder struct { + mock *MockHttpFilterConfigFactory +} + +// NewMockHttpFilterConfigFactory creates a new mock instance. +func NewMockHttpFilterConfigFactory(ctrl *gomock.Controller) *MockHttpFilterConfigFactory { + mock := &MockHttpFilterConfigFactory{ctrl: ctrl} + mock.recorder = &MockHttpFilterConfigFactoryMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockHttpFilterConfigFactory) EXPECT() *MockHttpFilterConfigFactoryMockRecorder { + return m.recorder +} + +// Create mocks base method. +func (m *MockHttpFilterConfigFactory) Create(handle shared.HttpFilterConfigHandle, unparsedConfig []byte) (shared.HttpFilterFactory, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Create", handle, unparsedConfig) + ret0, _ := ret[0].(shared.HttpFilterFactory) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Create indicates an expected call of Create. +func (mr *MockHttpFilterConfigFactoryMockRecorder) Create(handle, unparsedConfig any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockHttpFilterConfigFactory)(nil).Create), handle, unparsedConfig) +} + +// CreatePerRoute mocks base method. +func (m *MockHttpFilterConfigFactory) CreatePerRoute(unparsedConfig []byte) (any, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreatePerRoute", unparsedConfig) + ret0, _ := ret[0].(any) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreatePerRoute indicates an expected call of CreatePerRoute. +func (mr *MockHttpFilterConfigFactoryMockRecorder) CreatePerRoute(unparsedConfig any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreatePerRoute", reflect.TypeOf((*MockHttpFilterConfigFactory)(nil).CreatePerRoute), unparsedConfig) +} diff --git a/test/extensions/dynamic_modules/http/BUILD b/test/extensions/dynamic_modules/http/BUILD index ee843fdf6a6e2..474698681d0e3 100644 --- a/test/extensions/dynamic_modules/http/BUILD +++ b/test/extensions/dynamic_modules/http/BUILD @@ -90,12 +90,6 @@ envoy_cc_test( deps = [ "//envoy/registry", "//source/common/router:string_accessor_lib", - # The Go SDK's `abi` Go package references every surface's - # `envoy_dynamic_module_callback_*` symbols, so any Go test_data .so has - # unresolved cross-surface callback references. With RTLD_LAZY the loader - # accepts these as long as the test binary provides them. all_abi_impls - # aggregates every per-surface `abi_impl`/`filter_lib`/`*_lib` library so a - # single dep gives the test binary the complete callback symbol surface. "//source/extensions/dynamic_modules:all_abi_impls", "//source/extensions/filters/http/dynamic_modules:filter_lib", "//test/extensions/dynamic_modules:util", @@ -156,7 +150,6 @@ envoy_cc_test( rbe_pool = "6gig", deps = [ "//source/common/config:metadata_lib", - # See comment on filter_test above for why we link every per-surface abi_impl. "//source/extensions/dynamic_modules:all_abi_impls", "//source/extensions/filters/http/dynamic_modules:factory_registration", "//test/extensions/dynamic_modules:util", diff --git a/test/extensions/dynamic_modules/network/BUILD b/test/extensions/dynamic_modules/network/BUILD index c6241a4a0ffd6..31c202939e310 100644 --- a/test/extensions/dynamic_modules/network/BUILD +++ b/test/extensions/dynamic_modules/network/BUILD @@ -83,8 +83,6 @@ envoy_cc_test( env = {"GODEBUG": "cgocheck=0"}, rbe_pool = "6gig", deps = [ - # See //test/extensions/dynamic_modules/http:filter_test for why every test - # binary that loads a Go test_data .so depends on all_abi_impls. "//source/extensions/dynamic_modules:all_abi_impls", "//source/extensions/filters/network/dynamic_modules:config", "//source/extensions/filters/network/tcp_proxy:config", diff --git a/test/extensions/dynamic_modules/test_data/go/test_data.bzl b/test/extensions/dynamic_modules/test_data/go/test_data.bzl index 5040bd2c2d09d..4998281bc42cf 100644 --- a/test/extensions/dynamic_modules/test_data/go/test_data.bzl +++ b/test/extensions/dynamic_modules/test_data/go/test_data.bzl @@ -1,14 +1,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_binary") -# Builds a Go-based test_data dynamic module as a c-shared .so. -# -# The Go SDK's `abi/*.go` files reference all of Envoy's per-surface -# `envoy_dynamic_module_callback_*` symbols. When a test binary loads the .so but only -# links a subset of the matching `abi_impl` C++ libraries, the unresolved references -# would break dlopen on Linux. The `-Wl,--unresolved-symbols=ignore-all` linker flag -# tells the dynamic linker to allow these unresolved symbols at load time; they're -# resolved lazily when the module actually invokes them, and any genuinely missing -# symbol surfaces as a clear error at first call rather than at dlopen. +# This declares a cc_library target that is used to build a shared library. +# name + ".c" is the source file that is compiled to create the shared library. def test_program(name): go_binary( name = name, From 8e1778a4a24e38f1f6236ae45429c844519d0e26 Mon Sep 17 00:00:00 2001 From: Adam Anderson <6754028+AdamEAnderson@users.noreply.github.com> Date: Tue, 19 May 2026 21:30:07 +0000 Subject: [PATCH 3/5] clean up diff Signed-off-by: Adam Anderson <6754028+AdamEAnderson@users.noreply.github.com> --- .../dynamic_modules/sdk/go/abi/http.go | 335 +++++++++++------- .../dynamic_modules/sdk/go/abi/network.go | 14 +- .../dynamic_modules/sdk/go/abi/scheduler.go | 7 +- .../dynamic_modules/sdk/go/shared/http_api.go | 9 +- .../dynamic_modules/http/integration_test.cc | 15 - 5 files changed, 215 insertions(+), 165 deletions(-) diff --git a/source/extensions/dynamic_modules/sdk/go/abi/http.go b/source/extensions/dynamic_modules/sdk/go/abi/http.go index d3701eaaface2..bab701508a54b 100644 --- a/source/extensions/dynamic_modules/sdk/go/abi/http.go +++ b/source/extensions/dynamic_modules/sdk/go/abi/http.go @@ -16,6 +16,7 @@ import ( _ "embed" "fmt" "runtime" + "strconv" "sync" "unsafe" @@ -32,6 +33,12 @@ type httpFilterConfigWrapperPerRoute struct { config any } +type httpFilterWrapper = dymHttpFilterHandle + +type httpFilterSharedDataWrapper struct { + data any +} + const numManagerShards = 32 // The managers to keep track of configs and plugins. @@ -45,19 +52,16 @@ func (m *manager[T]) record(item *T) unsafe.Pointer { index := uintptr(pointer) % numManagerShards m.mutex[index].Lock() defer m.mutex[index].Unlock() + // Assume the map is initialized. m.data[index][uintptr(pointer)] = item return pointer } -// unwrap returns the live wrapper for the given pointer key, or nil if the wrapper is no -// longer registered (e.g., remove already ran). Callers MUST handle a nil return — a stale -// pointer cast would otherwise alias freed memory and crash or corrupt unrelated state when -// Envoy delivers a late callback after destroy. func (m *manager[T]) unwrap(itemPtr unsafe.Pointer) *T { - if itemPtr == nil { - return nil - } - key := uintptr(itemPtr) + return (*T)(itemPtr) +} + +func (m *manager[T]) search(key uintptr) *T { index := key % numManagerShards m.mutex[index].Lock() defer m.mutex[index].Unlock() @@ -81,7 +85,8 @@ func newManager[T any]() *manager[T] { var configManager = newManager[httpFilterConfigWrapper]() var configPerRouteManager = newManager[httpFilterConfigWrapperPerRoute]() -var pluginManager = newManager[dymHttpFilterHandle]() +var pluginManager = newManager[httpFilterWrapper]() +var sharedDataManager = newManager[httpFilterSharedDataWrapper]() //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -198,7 +203,7 @@ func envoyBufferSliceToUnsafeEnvoyBufferSlice( func hostLog(level shared.LogLevel, format string, args []any) { logLevel := uint32(level) - // Skip Sprintf if logging at this level is disabled. + // Quick check if logging is enabled at this level. if !bool(C.envoy_dynamic_module_callback_log_enabled( (C.envoy_dynamic_module_type_log_level)(logLevel), )) { @@ -302,7 +307,7 @@ func (h *dymHeaderMap) Add(key, value string) { } func (h *dymHeaderMap) Remove(key string) { - // The ABI removes a header by setting its value to a null buffer. + // The ABI use the set to nil to remove the header. C.envoy_dynamic_module_callback_http_set_header( (C.envoy_dynamic_module_type_http_filter_envoy_ptr)(h.hostPluginPtr), (C.envoy_dynamic_module_type_http_header_type)(h.headerType), @@ -371,12 +376,15 @@ func (b *dymBodyBuffer) Drain(size uint64) { // child spans spawned from this span can be tracked on the owning filter handle and safely // retired when the stream is destroyed. type dymSpan struct { - spanPtr C.envoy_dynamic_module_type_span_envoy_ptr hostPluginPtr C.envoy_dynamic_module_type_http_filter_envoy_ptr + spanPtr C.envoy_dynamic_module_type_span_envoy_ptr filter *dymHttpFilterHandle } func (s *dymSpan) SetTag(key, value string) { + if s == nil || s.spanPtr == nil { + return + } C.envoy_dynamic_module_callback_http_span_set_tag( s.spanPtr, stringToModuleBuffer(key), @@ -387,6 +395,9 @@ func (s *dymSpan) SetTag(key, value string) { } func (s *dymSpan) SetOperation(operation string) { + if s == nil || s.spanPtr == nil { + return + } C.envoy_dynamic_module_callback_http_span_set_operation( s.spanPtr, stringToModuleBuffer(operation), @@ -395,6 +406,9 @@ func (s *dymSpan) SetOperation(operation string) { } func (s *dymSpan) Log(event string) { + if s == nil || s.spanPtr == nil { + return + } C.envoy_dynamic_module_callback_http_span_log( s.hostPluginPtr, s.spanPtr, @@ -404,13 +418,16 @@ func (s *dymSpan) Log(event string) { } func (s *dymSpan) SetSampled(sampled bool) { - C.envoy_dynamic_module_callback_http_span_set_sampled( - s.spanPtr, - (C.bool)(sampled), - ) + if s == nil || s.spanPtr == nil { + return + } + C.envoy_dynamic_module_callback_http_span_set_sampled(s.spanPtr, C.bool(sampled)) } func (s *dymSpan) GetBaggage(key string) (shared.UnsafeEnvoyBuffer, bool) { + if s == nil || s.spanPtr == nil { + return shared.UnsafeEnvoyBuffer{}, false + } var valueView C.envoy_dynamic_module_type_envoy_buffer ret := C.envoy_dynamic_module_callback_http_span_get_baggage( s.spanPtr, @@ -418,13 +435,19 @@ func (s *dymSpan) GetBaggage(key string) (shared.UnsafeEnvoyBuffer, bool) { &valueView, ) runtime.KeepAlive(key) - if !bool(ret) || valueView.ptr == nil || valueView.length == 0 { - return shared.UnsafeEnvoyBuffer{}, bool(ret) + if !bool(ret) { + return shared.UnsafeEnvoyBuffer{}, false + } + if valueView.ptr == nil || valueView.length == 0 { + return shared.UnsafeEnvoyBuffer{}, true } return envoyBufferToUnsafeEnvoyBuffer(valueView), true } func (s *dymSpan) SetBaggage(key, value string) { + if s == nil || s.spanPtr == nil { + return + } C.envoy_dynamic_module_callback_http_span_set_baggage( s.spanPtr, stringToModuleBuffer(key), @@ -435,36 +458,45 @@ func (s *dymSpan) SetBaggage(key, value string) { } func (s *dymSpan) GetTraceID() (shared.UnsafeEnvoyBuffer, bool) { + if s == nil || s.spanPtr == nil { + return shared.UnsafeEnvoyBuffer{}, false + } var valueView C.envoy_dynamic_module_type_envoy_buffer - ret := C.envoy_dynamic_module_callback_http_span_get_trace_id( - s.spanPtr, - &valueView, - ) - if !bool(ret) || valueView.ptr == nil || valueView.length == 0 { - return shared.UnsafeEnvoyBuffer{}, bool(ret) + ret := C.envoy_dynamic_module_callback_http_span_get_trace_id(s.spanPtr, &valueView) + if !bool(ret) { + return shared.UnsafeEnvoyBuffer{}, false + } + if valueView.ptr == nil || valueView.length == 0 { + return shared.UnsafeEnvoyBuffer{}, true } return envoyBufferToUnsafeEnvoyBuffer(valueView), true } func (s *dymSpan) GetSpanID() (shared.UnsafeEnvoyBuffer, bool) { + if s == nil || s.spanPtr == nil { + return shared.UnsafeEnvoyBuffer{}, false + } var valueView C.envoy_dynamic_module_type_envoy_buffer - ret := C.envoy_dynamic_module_callback_http_span_get_span_id( - s.spanPtr, - &valueView, - ) - if !bool(ret) || valueView.ptr == nil || valueView.length == 0 { - return shared.UnsafeEnvoyBuffer{}, bool(ret) + ret := C.envoy_dynamic_module_callback_http_span_get_span_id(s.spanPtr, &valueView) + if !bool(ret) { + return shared.UnsafeEnvoyBuffer{}, false + } + if valueView.ptr == nil || valueView.length == 0 { + return shared.UnsafeEnvoyBuffer{}, true } return envoyBufferToUnsafeEnvoyBuffer(valueView), true } -func (s *dymSpan) SpawnChild(operationName string) shared.ChildSpan { +func (s *dymSpan) SpawnChild(operation string) shared.ChildSpan { + if s == nil || s.spanPtr == nil { + return nil + } childPtr := C.envoy_dynamic_module_callback_http_span_spawn_child( s.hostPluginPtr, s.spanPtr, - stringToModuleBuffer(operationName), + stringToModuleBuffer(operation), ) - runtime.KeepAlive(operationName) + runtime.KeepAlive(operation) if childPtr == nil { return nil } @@ -486,8 +518,6 @@ type dymChildSpan struct { finished bool } -// asSpanPtr returns the child span as the generic span pointer accepted by the span_* callbacks. -// In the ABI both pointer types are void*, and Envoy resolves the right type via dynamic_cast. func (c *dymChildSpan) asSpanPtr() C.envoy_dynamic_module_type_span_envoy_ptr { return C.envoy_dynamic_module_type_span_envoy_ptr(c.childPtr) } @@ -579,19 +609,12 @@ type dymHttpFilterHandle struct { plugin shared.HttpFilter scheduler *dymScheduler streamCompleted bool - streamDestroyed bool localResponseSent bool - // calloutCallbacks/streamCallbacks/data are accessed only from the worker thread that - // owns the stream — Envoy invokes filter callbacks and dispatches callout completions - // on the same thread, so no synchronization is needed. calloutCallbacks map[uint64]shared.HttpCalloutCallback streamCallbacks map[uint64]shared.HttpStreamCallback - // data backs SetData/GetData — per-stream module-private state for cross-phase - // communication. Held in Go memory rather than smuggled through Envoy dynamic metadata - // (which would expose the storage to other filters and observers). - data map[string]any + recordedSharedData []unsafe.Pointer downstreamWatermarkCallbacks shared.DownstreamWatermarkCallbacks @@ -602,8 +625,6 @@ type dymHttpFilterHandle struct { childSpans map[*dymChildSpan]struct{} } -// trackChildSpan registers a child span so it will be finished if the stream is destroyed -// before the module calls Finish on it. func (h *dymHttpFilterHandle) trackChildSpan(c *dymChildSpan) { if h.childSpans == nil { h.childSpans = make(map[*dymChildSpan]struct{}) @@ -611,14 +632,10 @@ func (h *dymHttpFilterHandle) trackChildSpan(c *dymChildSpan) { h.childSpans[c] = struct{}{} } -// untrackChildSpan removes a child span from the wrapper's tracking set after the user -// calls Finish on it. func (h *dymHttpFilterHandle) untrackChildSpan(c *dymChildSpan) { delete(h.childSpans, c) } -// finishChildSpansOnDestroy is called from the stream-destroy hook. It finishes every -// span the module forgot, releasing the host-side Tracing::Span allocations. func (h *dymHttpFilterHandle) finishChildSpansOnDestroy() { for c := range h.childSpans { if !c.finished { @@ -823,6 +840,7 @@ func (h *dymHttpFilterHandle) GetMetadataListString(source shared.MetadataSource if !bool(ret) { return shared.UnsafeEnvoyBuffer{}, false } + // Handle the case where the value is empty string. if valueView.ptr == nil || valueView.length == 0 { return shared.UnsafeEnvoyBuffer{}, true } @@ -985,8 +1003,11 @@ func (h *dymHttpFilterHandle) GetFilterStateTyped(key string) (shared.UnsafeEnvo &valueView, ) runtime.KeepAlive(key) - if !bool(ret) || valueView.ptr == nil || valueView.length == 0 { - return shared.UnsafeEnvoyBuffer{}, bool(ret) + if !bool(ret) { + return shared.UnsafeEnvoyBuffer{}, false + } + if valueView.ptr == nil || valueView.length == 0 { + return shared.UnsafeEnvoyBuffer{}, true } return envoyBufferToUnsafeEnvoyBuffer(valueView), true } @@ -1029,14 +1050,41 @@ func (h *dymHttpFilterHandle) SetFilterStateTyped(key string, value []byte) bool } func (h *dymHttpFilterHandle) GetData(key string) any { - return h.data[key] + buf, found := h.GetMetadataString(shared.MetadataSourceTypeDynamic, + "composer.shared_data", key) + if !found { + return nil + } + // Convert string back to uintptr safely. + uintValue, err := strconv.ParseUint(buf.ToUnsafeString(), 10, 64) + if err != nil { + return nil + } + pointer := uintptr(uintValue) + // Use search rather than unwrap because the go runtime will complain + // the pointer parsed from string `pointer arithmetic result points to invalid allocation`. + wrapper := sharedDataManager.search(pointer) + if wrapper == nil { + return nil + } + return wrapper.data } func (h *dymHttpFilterHandle) SetData(key string, value any) { - if h.data == nil { - h.data = make(map[string]any) + wrapper := &httpFilterSharedDataWrapper{data: value} + pointer := sharedDataManager.record(wrapper) + h.recordedSharedData = append(h.recordedSharedData, pointer) + + // Covert pointer to uintptr to string safely. + stringValue := strconv.FormatUint(uint64(uintptr(pointer)), 10) + h.SetMetadata("composer.shared_data", key, stringValue) +} + +func (h *dymHttpFilterHandle) clearData() { + for _, pointer := range h.recordedSharedData { + sharedDataManager.remove(pointer) } - h.data[key] = value + h.recordedSharedData = nil } func (h *dymHttpFilterHandle) SendLocalResponse( @@ -1047,6 +1095,7 @@ func (h *dymHttpFilterHandle) SendLocalResponse( ) { h.localResponseSent = true + // Prepare headers. headerViews := headersToModuleHttpHeaderSlice(headers) C.envoy_dynamic_module_callback_http_send_response( h.hostPluginPtr, @@ -1065,6 +1114,7 @@ func (h *dymHttpFilterHandle) SendLocalResponse( func (h *dymHttpFilterHandle) SendResponseHeaders( headers [][2]string, endOfStream bool, ) { + // Prepare headers. headerViews := headersToModuleHttpHeaderSlice(headers) C.envoy_dynamic_module_callback_http_send_response_headers( h.hostPluginPtr, @@ -1090,6 +1140,7 @@ func (h *dymHttpFilterHandle) SendResponseData( func (h *dymHttpFilterHandle) SendResponseTrailers( trailers [][2]string, ) { + // Prepare trailers. trailerViews := headersToModuleHttpHeaderSlice(trailers) C.envoy_dynamic_module_callback_http_send_response_trailers( h.hostPluginPtr, @@ -1128,35 +1179,38 @@ func (h *dymHttpFilterHandle) RefreshRouteCluster() { } func (h *dymHttpFilterHandle) GetWorkerIndex() uint32 { - return uint32(C.envoy_dynamic_module_callback_http_filter_get_worker_index( - h.hostPluginPtr, - )) + return uint32(C.envoy_dynamic_module_callback_http_filter_get_worker_index(h.hostPluginPtr)) } func (h *dymHttpFilterHandle) SetSocketOptionInt( - level, name int64, state shared.SocketOptionState, - direction shared.SocketDirection, value int64, + level, name int64, + state shared.SocketOptionState, + direction shared.SocketDirection, + value int64, ) bool { - return bool(C.envoy_dynamic_module_callback_http_set_socket_option_int( + ret := C.envoy_dynamic_module_callback_http_set_socket_option_int( h.hostPluginPtr, - (C.int64_t)(level), - (C.int64_t)(name), - (C.envoy_dynamic_module_type_socket_option_state)(state), - (C.envoy_dynamic_module_type_socket_direction)(direction), - (C.int64_t)(value), - )) + C.int64_t(level), + C.int64_t(name), + C.envoy_dynamic_module_type_socket_option_state(state), + C.envoy_dynamic_module_type_socket_direction(direction), + C.int64_t(value), + ) + return bool(ret) } func (h *dymHttpFilterHandle) SetSocketOptionBytes( - level, name int64, state shared.SocketOptionState, - direction shared.SocketDirection, value []byte, + level, name int64, + state shared.SocketOptionState, + direction shared.SocketDirection, + value []byte, ) bool { ret := C.envoy_dynamic_module_callback_http_set_socket_option_bytes( h.hostPluginPtr, - (C.int64_t)(level), - (C.int64_t)(name), - (C.envoy_dynamic_module_type_socket_option_state)(state), - (C.envoy_dynamic_module_type_socket_direction)(direction), + C.int64_t(level), + C.int64_t(name), + C.envoy_dynamic_module_type_socket_option_state(state), + C.envoy_dynamic_module_type_socket_direction(direction), bytesToModuleBuffer(value), ) runtime.KeepAlive(value) @@ -1164,16 +1218,17 @@ func (h *dymHttpFilterHandle) SetSocketOptionBytes( } func (h *dymHttpFilterHandle) GetSocketOptionInt( - level, name int64, state shared.SocketOptionState, + level, name int64, + state shared.SocketOptionState, direction shared.SocketDirection, ) (int64, bool) { - var value C.int64_t = 0 + var value C.int64_t ret := C.envoy_dynamic_module_callback_http_get_socket_option_int( h.hostPluginPtr, - (C.int64_t)(level), - (C.int64_t)(name), - (C.envoy_dynamic_module_type_socket_option_state)(state), - (C.envoy_dynamic_module_type_socket_direction)(direction), + C.int64_t(level), + C.int64_t(name), + C.envoy_dynamic_module_type_socket_option_state(state), + C.envoy_dynamic_module_type_socket_direction(direction), &value, ) if !bool(ret) { @@ -1183,68 +1238,67 @@ func (h *dymHttpFilterHandle) GetSocketOptionInt( } func (h *dymHttpFilterHandle) GetSocketOptionBytes( - level, name int64, state shared.SocketOptionState, + level, name int64, + state shared.SocketOptionState, direction shared.SocketDirection, ) (shared.UnsafeEnvoyBuffer, bool) { var valueView C.envoy_dynamic_module_type_envoy_buffer ret := C.envoy_dynamic_module_callback_http_get_socket_option_bytes( h.hostPluginPtr, - (C.int64_t)(level), - (C.int64_t)(name), - (C.envoy_dynamic_module_type_socket_option_state)(state), - (C.envoy_dynamic_module_type_socket_direction)(direction), + C.int64_t(level), + C.int64_t(name), + C.envoy_dynamic_module_type_socket_option_state(state), + C.envoy_dynamic_module_type_socket_direction(direction), &valueView, ) - if !bool(ret) || valueView.ptr == nil || valueView.length == 0 { - return shared.UnsafeEnvoyBuffer{}, bool(ret) + if !bool(ret) { + return shared.UnsafeEnvoyBuffer{}, false + } + if valueView.ptr == nil || valueView.length == 0 { + return shared.UnsafeEnvoyBuffer{}, true } return envoyBufferToUnsafeEnvoyBuffer(valueView), true } func (h *dymHttpFilterHandle) GetBufferLimit() uint64 { - return uint64(C.envoy_dynamic_module_callback_http_get_buffer_limit( - h.hostPluginPtr, - )) + return uint64(C.envoy_dynamic_module_callback_http_get_buffer_limit(h.hostPluginPtr)) } func (h *dymHttpFilterHandle) SetBufferLimit(limit uint64) { - C.envoy_dynamic_module_callback_http_set_buffer_limit( - h.hostPluginPtr, - (C.uint64_t)(limit), - ) + C.envoy_dynamic_module_callback_http_set_buffer_limit(h.hostPluginPtr, C.uint64_t(limit)) } func (h *dymHttpFilterHandle) GetActiveSpan() shared.Span { - spanPtr := C.envoy_dynamic_module_callback_http_get_active_span( - h.hostPluginPtr, - ) + spanPtr := C.envoy_dynamic_module_callback_http_get_active_span(h.hostPluginPtr) if spanPtr == nil { return nil } return &dymSpan{ - spanPtr: spanPtr, hostPluginPtr: h.hostPluginPtr, + spanPtr: spanPtr, filter: h, } } func (h *dymHttpFilterHandle) GetClusterName() (shared.UnsafeEnvoyBuffer, bool) { var valueView C.envoy_dynamic_module_type_envoy_buffer - ret := C.envoy_dynamic_module_callback_http_get_cluster_name( - h.hostPluginPtr, - &valueView, - ) - if !bool(ret) || valueView.ptr == nil || valueView.length == 0 { - return shared.UnsafeEnvoyBuffer{}, bool(ret) + ret := C.envoy_dynamic_module_callback_http_get_cluster_name(h.hostPluginPtr, &valueView) + if !bool(ret) { + return shared.UnsafeEnvoyBuffer{}, false + } + if valueView.ptr == nil || valueView.length == 0 { + return shared.UnsafeEnvoyBuffer{}, true } return envoyBufferToUnsafeEnvoyBuffer(valueView), true } func (h *dymHttpFilterHandle) GetClusterHostCounts(priority uint32) (shared.ClusterHostCounts, bool) { - var total, healthy, degraded C.size_t + var total C.size_t + var healthy C.size_t + var degraded C.size_t ret := C.envoy_dynamic_module_callback_http_get_cluster_host_count( h.hostPluginPtr, - (C.uint32_t)(priority), + C.uint32_t(priority), &total, &healthy, °raded, @@ -1263,7 +1317,7 @@ func (h *dymHttpFilterHandle) SetUpstreamOverrideHost(host string, strict bool) ret := C.envoy_dynamic_module_callback_http_set_upstream_override_host( h.hostPluginPtr, stringToModuleBuffer(host), - (C.bool)(strict), + C.bool(strict), ) runtime.KeepAlive(host) return bool(ret) @@ -1272,7 +1326,7 @@ func (h *dymHttpFilterHandle) SetUpstreamOverrideHost(host string, strict bool) func (h *dymHttpFilterHandle) ResetStream(reason shared.HttpFilterStreamResetReason, details string) { C.envoy_dynamic_module_callback_http_filter_reset_stream( h.hostPluginPtr, - (C.envoy_dynamic_module_type_http_filter_stream_reset_reason)(reason), + C.envoy_dynamic_module_type_http_filter_stream_reset_reason(reason), stringToModuleBuffer(details), ) runtime.KeepAlive(details) @@ -1281,23 +1335,16 @@ func (h *dymHttpFilterHandle) ResetStream(reason shared.HttpFilterStreamResetRea func (h *dymHttpFilterHandle) SendGoAwayAndClose(graceful bool) { C.envoy_dynamic_module_callback_http_filter_send_go_away_and_close( h.hostPluginPtr, - (C.bool)(graceful), + C.bool(graceful), ) } func (h *dymHttpFilterHandle) RecreateStream(headers [][2]string) bool { - if len(headers) == 0 { - return bool(C.envoy_dynamic_module_callback_http_filter_recreate_stream( - h.hostPluginPtr, - nil, - 0, - )) - } headerViews := headersToModuleHttpHeaderSlice(headers) ret := C.envoy_dynamic_module_callback_http_filter_recreate_stream( h.hostPluginPtr, unsafe.SliceData(headerViews), - (C.size_t)(len(headerViews)), + C.size_t(len(headerViews)), ) runtime.KeepAlive(headers) runtime.KeepAlive(headerViews) @@ -1361,6 +1408,8 @@ func (h *dymHttpFilterHandle) GetMostSpecificConfig() any { func (h *dymHttpFilterHandle) GetScheduler() shared.Scheduler { if h.scheduler == nil { + // The scheduler is created lazily and should never be nil + // in practice. But it will be nil in mock tests. schedulerPtr := C.envoy_dynamic_module_callback_http_filter_scheduler_new( h.hostPluginPtr) h.scheduler = newDymScheduler( @@ -1388,6 +1437,7 @@ func (h *dymHttpFilterHandle) Log(level shared.LogLevel, format string, args ... func (h *dymHttpFilterHandle) HttpCallout( cluster string, headers [][2]string, body []byte, timeoutMs uint64, cb shared.HttpCalloutCallback) (shared.HttpCalloutInitResult, uint64) { + // Prepare headers. headerViews := headersToModuleHttpHeaderSlice(headers) var calloutID C.uint64_t = 0 @@ -1422,6 +1472,7 @@ func (h *dymHttpFilterHandle) HttpCallout( func (h *dymHttpFilterHandle) StartHttpStream( cluster string, headers [][2]string, body []byte, endOfStream bool, timeoutMs uint64, cb shared.HttpStreamCallback) (shared.HttpCalloutInitResult, uint64) { + // Prepare headers. headerViews := headersToModuleHttpHeaderSlice(headers) var streamID C.uint64_t = 0 @@ -1470,6 +1521,7 @@ func (h *dymHttpFilterHandle) SendHttpStreamData( func (h *dymHttpFilterHandle) SendHttpStreamTrailers( streamID uint64, trailers [][2]string, ) bool { + // Prepare trailers. trailerViews := headersToModuleHttpHeaderSlice(trailers) ret := C.envoy_dynamic_module_callback_http_stream_send_trailers( h.hostPluginPtr, @@ -1504,6 +1556,7 @@ func (h *dymHttpFilterHandle) ClearDownstreamWatermarkCallbacks() { func (h *dymHttpFilterHandle) RecordHistogramValue(id shared.MetricID, value uint64, tagsValues ...string) shared.MetricsResult { idUint64 := uint64(id) + // Prepare tag values. tagValueViews := stringArrayToModuleBufferSlice(tagsValues) ret := C.envoy_dynamic_module_callback_http_filter_record_histogram_value( @@ -1522,6 +1575,7 @@ func (h *dymHttpFilterHandle) RecordHistogramValue(id shared.MetricID, func (h *dymHttpFilterHandle) SetGaugeValue(id shared.MetricID, value uint64, tagsValues ...string) shared.MetricsResult { idUint64 := uint64(id) + // Prepare tag values. tagValueViews := stringArrayToModuleBufferSlice(tagsValues) ret := C.envoy_dynamic_module_callback_http_filter_set_gauge( @@ -1539,6 +1593,7 @@ func (h *dymHttpFilterHandle) SetGaugeValue(id shared.MetricID, func (h *dymHttpFilterHandle) IncrementGaugeValue(id shared.MetricID, value uint64, tagsValues ...string) shared.MetricsResult { + // Prepare tag values. tagValueViews := stringArrayToModuleBufferSlice(tagsValues) ret := C.envoy_dynamic_module_callback_http_filter_increment_gauge( h.hostPluginPtr, @@ -1554,6 +1609,7 @@ func (h *dymHttpFilterHandle) IncrementGaugeValue(id shared.MetricID, func (h *dymHttpFilterHandle) DecrementGaugeValue(id shared.MetricID, value uint64, tagsValues ...string) shared.MetricsResult { + // Prepare tag values. tagValueViews := stringArrayToModuleBufferSlice(tagsValues) ret := C.envoy_dynamic_module_callback_http_filter_decrement_gauge( h.hostPluginPtr, @@ -1569,6 +1625,7 @@ func (h *dymHttpFilterHandle) DecrementGaugeValue(id shared.MetricID, func (h *dymHttpFilterHandle) IncrementCounterValue(id shared.MetricID, value uint64, tagsValues ...string) shared.MetricsResult { + // Prepare tag values. tagValueViews := stringArrayToModuleBufferSlice(tagsValues) ret := C.envoy_dynamic_module_callback_http_filter_increment_counter( h.hostPluginPtr, @@ -1624,9 +1681,7 @@ func newDymStreamPluginHandle( } type dymConfigHandle struct { - hostConfigPtr C.envoy_dynamic_module_type_http_filter_config_envoy_ptr - // calloutCallbacks/streamCallbacks are accessed only on the main thread — config-level - // callouts both initiate and complete via main_thread_dispatcher_, so no locking needed. + hostConfigPtr C.envoy_dynamic_module_type_http_filter_config_envoy_ptr calloutCallbacks map[uint64]shared.HttpCalloutCallback streamCallbacks map[uint64]shared.HttpStreamCallback scheduler *dymScheduler @@ -1638,6 +1693,7 @@ func (h *dymConfigHandle) Log(level shared.LogLevel, format string, args ...any) func (h *dymConfigHandle) DefineHistogram(name string, tagKeys ...string) (shared.MetricID, shared.MetricsResult) { + // Prepare tag keys. tagKeyViews := stringArrayToModuleBufferSlice(tagKeys) var metricID C.size_t = 0 @@ -1663,6 +1719,7 @@ func (h *dymConfigHandle) DefineHistogram(name string, func (h *dymConfigHandle) DefineGauge(name string, tagKeys ...string) (shared.MetricID, shared.MetricsResult) { + // Prepare tag keys. tagKeyViews := stringArrayToModuleBufferSlice(tagKeys) var metricID C.size_t = 0 @@ -1687,6 +1744,7 @@ func (h *dymConfigHandle) DefineGauge(name string, func (h *dymConfigHandle) DefineCounter(name string, tagKeys ...string) (shared.MetricID, shared.MetricsResult) { + // Prepare tag keys. tagKeyViews := stringArrayToModuleBufferSlice(tagKeys) var metricID C.size_t = 0 @@ -1811,6 +1869,8 @@ func (h *dymConfigHandle) ResetHttpStream(streamID uint64) { func (h *dymConfigHandle) GetScheduler() shared.Scheduler { if h.scheduler == nil { + // The scheduler is created lazily and should never be nil + // in practice. But it will be nil in mock tests. schedulerPtr := C.envoy_dynamic_module_callback_http_filter_config_scheduler_new( h.hostConfigPtr) h.scheduler = newDymScheduler( @@ -1885,9 +1945,6 @@ func envoy_dynamic_module_on_http_filter_config_destroy( configPtr C.envoy_dynamic_module_type_http_filter_config_module_ptr, ) { factoryWrapper := configManager.unwrap(unsafe.Pointer(configPtr)) - if factoryWrapper == nil { - return - } if factoryWrapper.configHandle.scheduler != nil { factoryWrapper.configHandle.scheduler.close() factoryWrapper.configHandle.scheduler = nil @@ -1904,6 +1961,7 @@ func envoy_dynamic_module_on_http_filter_per_route_config_new( nameStr := envoyBufferToStringUnsafe(name) configBytes := envoyBufferToBytesCopy(config) + // The route config handle only make logging available. configHandle := &dymRouteConfigHandle{} configFactory := sdk.GetHttpFilterConfigFactory(nameStr) @@ -1944,6 +2002,8 @@ func envoy_dynamic_module_on_http_filter_new( if factoryWrapper == nil { return nil } + + // Create the plugin wrapper. pluginWrapper := newDymStreamPluginHandle(hostPluginPtr) pluginWrapper.plugin = factoryWrapper.pluginFactory.Create(pluginWrapper) @@ -1956,11 +2016,11 @@ func envoy_dynamic_module_on_http_filter_destroy( pluginPtr C.envoy_dynamic_module_type_http_filter_module_ptr, ) { pluginWrapper := pluginManager.unwrap(unsafe.Pointer(pluginPtr)) - if pluginWrapper == nil || pluginWrapper.streamDestroyed { + if pluginWrapper == nil { return } - pluginWrapper.streamDestroyed = true pluginWrapper.finishChildSpansOnDestroy() + pluginWrapper.clearData() if pluginWrapper.plugin != nil { pluginWrapper.plugin.OnDestroy() } @@ -1973,6 +2033,7 @@ func envoy_dynamic_module_on_http_filter_request_headers( pluginPtr C.envoy_dynamic_module_type_http_filter_module_ptr, endOfStream C.bool, ) C.envoy_dynamic_module_type_on_http_filter_request_headers_status { + // Get the plugin wrapper. pluginWrapper := pluginManager.unwrap(unsafe.Pointer(pluginPtr)) if pluginWrapper == nil || pluginWrapper.plugin == nil { return 0 @@ -2060,13 +2121,12 @@ func envoy_dynamic_module_on_http_filter_stream_complete( return } pluginWrapper.streamCompleted = true + pluginWrapper.clearData() if pluginWrapper.scheduler != nil { pluginWrapper.scheduler.close() pluginWrapper.scheduler = nil } pluginWrapper.plugin.OnStreamComplete() - // data is held in Go memory and is freed when the wrapper is GC'd after pluginManager - // removes it; no explicit teardown is needed. } //export envoy_dynamic_module_on_http_filter_scheduled @@ -2098,6 +2158,7 @@ func envoy_dynamic_module_on_http_filter_http_callout_done( return } + // Prepare headers and body chunks. resultHeaders := envoyHttpHeaderSliceToUnsafeHeaderSlice(unsafe.Slice(headers, int(headersSize))) resultChunks := envoyBufferSliceToUnsafeEnvoyBufferSlice(unsafe.Slice(chunks, int(chunksSize))) @@ -2126,9 +2187,11 @@ func envoy_dynamic_module_on_http_filter_http_stream_headers( return } + // Prepare headers. resultHeaders := envoyHttpHeaderSliceToUnsafeHeaderSlice(unsafe.Slice(headers, int(headersSize))) - if cb := pluginWrapper.streamCallbacks[uint64(streamID)]; cb != nil { + cb := pluginWrapper.streamCallbacks[uint64(streamID)] + if cb != nil { cb.OnHttpStreamHeaders(uint64(streamID), resultHeaders, bool(endOfStream)) } } @@ -2147,9 +2210,11 @@ func envoy_dynamic_module_on_http_filter_http_stream_data( return } + // Prepare data. resultData := envoyBufferSliceToUnsafeEnvoyBufferSlice(unsafe.Slice(chunks, int(chunksSize))) - if cb := pluginWrapper.streamCallbacks[uint64(streamID)]; cb != nil { + cb := pluginWrapper.streamCallbacks[uint64(streamID)] + if cb != nil { cb.OnHttpStreamData(uint64(streamID), resultData, bool(endOfStream)) } } @@ -2167,9 +2232,11 @@ func envoy_dynamic_module_on_http_filter_http_stream_trailers( return } + // Prepare trailers. resultTrailers := envoyHttpHeaderSliceToUnsafeHeaderSlice(unsafe.Slice(trailers, int(trailersSize))) - if cb := pluginWrapper.streamCallbacks[uint64(streamID)]; cb != nil { + cb := pluginWrapper.streamCallbacks[uint64(streamID)] + if cb != nil { cb.OnHttpStreamTrailers(uint64(streamID), resultTrailers) } } @@ -2255,6 +2322,7 @@ func envoy_dynamic_module_on_http_filter_local_reply( shared.LocalReplyStatusContinue, ) } + return C.envoy_dynamic_module_type_on_http_filter_local_reply_status( pluginWrapper.plugin.OnLocalReply( uint32(response_code), @@ -2308,7 +2376,8 @@ func envoy_dynamic_module_on_http_filter_config_http_stream_headers( resultHeaders := envoyHttpHeaderSliceToUnsafeHeaderSlice(unsafe.Slice(headers, int(headersSize))) - if cb := ch.streamCallbacks[uint64(streamID)]; cb != nil { + cb := ch.streamCallbacks[uint64(streamID)] + if cb != nil { cb.OnHttpStreamHeaders(uint64(streamID), resultHeaders, bool(endOfStream)) } } @@ -2330,7 +2399,8 @@ func envoy_dynamic_module_on_http_filter_config_http_stream_data( resultData := envoyBufferSliceToUnsafeEnvoyBufferSlice(unsafe.Slice(chunks, int(chunksSize))) - if cb := ch.streamCallbacks[uint64(streamID)]; cb != nil { + cb := ch.streamCallbacks[uint64(streamID)] + if cb != nil { cb.OnHttpStreamData(uint64(streamID), resultData, bool(endOfStream)) } } @@ -2351,7 +2421,8 @@ func envoy_dynamic_module_on_http_filter_config_http_stream_trailers( resultTrailers := envoyHttpHeaderSliceToUnsafeHeaderSlice(unsafe.Slice(trailers, int(trailersSize))) - if cb := ch.streamCallbacks[uint64(streamID)]; cb != nil { + cb := ch.streamCallbacks[uint64(streamID)] + if cb != nil { cb.OnHttpStreamTrailers(uint64(streamID), resultTrailers) } } diff --git a/source/extensions/dynamic_modules/sdk/go/abi/network.go b/source/extensions/dynamic_modules/sdk/go/abi/network.go index 1759b20146326..88e397fbccfd3 100644 --- a/source/extensions/dynamic_modules/sdk/go/abi/network.go +++ b/source/extensions/dynamic_modules/sdk/go/abi/network.go @@ -20,8 +20,10 @@ type networkFilterConfigWrapper struct { configHandle *dymNetworkConfigHandle } +type networkFilterWrapper = dymNetworkFilterHandle + var networkConfigManager = newManager[networkFilterConfigWrapper]() -var networkPluginManager = newManager[dymNetworkFilterHandle]() +var networkPluginManager = newManager[networkFilterWrapper]() type dymNetworkBuffer struct { hostPluginPtr C.envoy_dynamic_module_type_network_filter_envoy_ptr @@ -128,12 +130,10 @@ func (b *dymNetworkBuffer) Append(data []byte) bool { } type dymNetworkFilterHandle struct { - hostPluginPtr C.envoy_dynamic_module_type_network_filter_envoy_ptr - plugin shared.NetworkFilter - readBuffer dymNetworkBuffer - writeBuffer dymNetworkBuffer - // calloutCallbacks is accessed only from the worker thread that owns the connection — - // Envoy invokes filter callbacks and dispatches callout completions on the same thread. + hostPluginPtr C.envoy_dynamic_module_type_network_filter_envoy_ptr + plugin shared.NetworkFilter + readBuffer dymNetworkBuffer + writeBuffer dymNetworkBuffer calloutCallbacks map[uint64]shared.HttpCalloutCallback scheduler *dymScheduler filterDestroyed bool diff --git a/source/extensions/dynamic_modules/sdk/go/abi/scheduler.go b/source/extensions/dynamic_modules/sdk/go/abi/scheduler.go index 336f67a71bdc1..83f66b66bd78d 100644 --- a/source/extensions/dynamic_modules/sdk/go/abi/scheduler.go +++ b/source/extensions/dynamic_modules/sdk/go/abi/scheduler.go @@ -13,18 +13,13 @@ import ( // dymScheduler is the SDK-side implementation of shared.Scheduler used by every extension // surface that exposes a NewScheduler method (HTTP filter, network filter, cluster, bootstrap, -// etc.). It is defined here rather than in http.go so that the type's home file reflects its -// cross-surface role. +// etc.). type dymScheduler struct { schedulerPtr unsafe.Pointer schedulerLock sync.Mutex nextTaskID uint64 tasks map[uint64]func() commitFunc func(unsafe.Pointer, C.uint64_t) - // deleteFunc invokes the host's *_scheduler_delete callback for this scheduler. - // Stored here so close() can free the host-side allocation synchronously from the - // destroy hook (the finalizer-only path leaks under LeakSanitizer because Go GC - // finalizers don't run on process exit). deleteFunc func(unsafe.Pointer) } diff --git a/source/extensions/dynamic_modules/sdk/go/shared/http_api.go b/source/extensions/dynamic_modules/sdk/go/shared/http_api.go index d18f8a31db6b3..301acefd6b9b2 100644 --- a/source/extensions/dynamic_modules/sdk/go/shared/http_api.go +++ b/source/extensions/dynamic_modules/sdk/go/shared/http_api.go @@ -70,12 +70,11 @@ const ( type LocalReplyStatus int32 const ( - // LocalReplyStatusContinue indicates that the local reply should continue to be sent - // after all filters are informed. + // LocalReplyStatusContinue indicates that the local reply should continue to be sent after all + // filters are informed. LocalReplyStatusContinue LocalReplyStatus = 0 - // LocalReplyStatusContinueAndResetStream indicates that the local reply notification - // should continue to all filters, but the stream should be reset instead of sending - // the local reply. + // LocalReplyStatusContinueAndResetStream indicates that the local reply notification should + // continue to all filters, but the stream should be reset instead of sending the local reply. LocalReplyStatusContinueAndResetStream LocalReplyStatus = 1 LocalReplyStatusDefault LocalReplyStatus = LocalReplyStatusContinue ) diff --git a/test/extensions/dynamic_modules/http/integration_test.cc b/test/extensions/dynamic_modules/http/integration_test.cc index bd2ccff9ee36b..2abef9e0729ac 100644 --- a/test/extensions/dynamic_modules/http/integration_test.cc +++ b/test/extensions/dynamic_modules/http/integration_test.cc @@ -1025,10 +1025,6 @@ TEST_P(DynamicModulesIntegrationTest, ConfigScheduler) { FAIL() << "Config was not updated in time"; } -// Verifies the config-time HttpCallout API: the filter config Create() initiates a -// callout via HttpFilterConfigHandle.HttpCallout against cluster_0. Per-request filters -// short-circuit with x-config-callout: success once the callout completes -// (503 + "pending" until then). TEST_P(DynamicModulesIntegrationTest, ConfigCallout) { // C++ SDK does not expose the config-time callout API; skip. if (GetParam() == "cpp") { @@ -1186,13 +1182,6 @@ TEST_P(DynamicModulesIntegrationTest, ListMetadataCallbacks) { EXPECT_EQ("false", bool_1[0]->value().getStringView()); } -// Verifies the scalar dynamic-metadata getters and SetMetadata. The route is configured -// with metadata under "test_ns" containing string/number/bool values; the filter reads -// them via Route source, writes them into Dynamic source under a test namespace, and on -// the response side reads them back from Dynamic source and surfaces them via headers. -// -// Verifies: GetMetadataString, GetMetadataNumber, GetMetadataBool, SetMetadata, -// GetMetadataKeys. TEST_P(DynamicModulesIntegrationTest, DynamicMetadata) { // C++ SDK doesn't currently surface the same scalar metadata API in its integration // module; skip. @@ -1239,10 +1228,6 @@ TEST_P(DynamicModulesIntegrationTest, DynamicMetadata) { EXPECT_EQ("3", count_hdr[0]->value().getStringView()); } -// Verifies SetFilterState/GetFilterState round-trip across filter boundaries: -// filter_state_writer (configured with "round_trip_value") sets a key on the request -// side; filter_state_reader (chained after) reads it on the request side and surfaces -// it via x-filter-state-value on the response. TEST_P(DynamicModulesIntegrationTest, FilterStateRoundTrip) { if (GetParam() == "cpp") { return; From c0d71299f6bea55baa616160296782bcc2b1a25e Mon Sep 17 00:00:00 2001 From: Adam Anderson <6754028+AdamEAnderson@users.noreply.github.com> Date: Tue, 19 May 2026 22:47:52 +0000 Subject: [PATCH 4/5] move api changes Signed-off-by: Adam Anderson <6754028+AdamEAnderson@users.noreply.github.com> --- source/extensions/dynamic_modules/BUILD | 5 +- .../dynamic_modules/sdk/go/abi/http.go | 93 +- .../sdk/go/shared/{http_api.go => api.go} | 45 +- .../dynamic_modules/sdk/go/shared/base.go | 873 +++++++++++++++ .../{fake_http.go => fake_stream_base.go} | 5 - ..._http_test.go => fake_stream_base_test.go} | 0 .../dynamic_modules/sdk/go/shared/http.go | 579 ---------- .../mocks/{mock_http_api.go => mock_api.go} | 4 +- .../mocks/{mock_http.go => mock_base.go} | 321 ++++-- .../sdk/go/shared/mocks/mock_network_api.go | 220 ---- .../sdk/go/shared/mocks/mock_network_base.go | 991 ------------------ .../sdk/go/shared/mocks/mock_types.go | 173 --- .../sdk/go/shared/network_api.go | 1 - .../sdk/go/shared/network_base.go | 1 - .../dynamic_modules/sdk/go/shared/types.go | 336 ------ 15 files changed, 1174 insertions(+), 2473 deletions(-) rename source/extensions/dynamic_modules/sdk/go/shared/{http_api.go => api.go} (82%) create mode 100644 source/extensions/dynamic_modules/sdk/go/shared/base.go rename source/extensions/dynamic_modules/sdk/go/shared/fake/{fake_http.go => fake_stream_base.go} (95%) rename source/extensions/dynamic_modules/sdk/go/shared/fake/{fake_http_test.go => fake_stream_base_test.go} (100%) delete mode 100644 source/extensions/dynamic_modules/sdk/go/shared/http.go rename source/extensions/dynamic_modules/sdk/go/shared/mocks/{mock_http_api.go => mock_api.go} (98%) rename source/extensions/dynamic_modules/sdk/go/shared/mocks/{mock_http.go => mock_base.go} (88%) delete mode 100644 source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_network_api.go delete mode 100644 source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_network_base.go delete mode 100644 source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_types.go delete mode 100644 source/extensions/dynamic_modules/sdk/go/shared/types.go diff --git a/source/extensions/dynamic_modules/BUILD b/source/extensions/dynamic_modules/BUILD index 3dddeafd513a8..0ac4b66f27c00 100644 --- a/source/extensions/dynamic_modules/BUILD +++ b/source/extensions/dynamic_modules/BUILD @@ -79,11 +79,10 @@ envoy_cc_library( go_library( name = "go_sdk_shared", srcs = [ - "sdk/go/shared/http.go", - "sdk/go/shared/http_api.go", + "sdk/go/shared/api.go", + "sdk/go/shared/base.go", "sdk/go/shared/network_api.go", "sdk/go/shared/network_base.go", - "sdk/go/shared/types.go", ], importpath = "github.com/envoyproxy/envoy/source/extensions/dynamic_modules/sdk/go/shared", visibility = ["//visibility:public"], diff --git a/source/extensions/dynamic_modules/sdk/go/abi/http.go b/source/extensions/dynamic_modules/sdk/go/abi/http.go index bab701508a54b..8e274bd51179d 100644 --- a/source/extensions/dynamic_modules/sdk/go/abi/http.go +++ b/source/extensions/dynamic_modules/sdk/go/abi/http.go @@ -371,10 +371,6 @@ func (b *dymBodyBuffer) Drain(size uint64) { ) } -// dymSpan implements shared.Span by wrapping the active span pointer for the current stream. -// The pointer is owned by Envoy and must not be finished by the module. filter is retained so -// child spans spawned from this span can be tracked on the owning filter handle and safely -// retired when the stream is destroyed. type dymSpan struct { hostPluginPtr C.envoy_dynamic_module_type_http_filter_envoy_ptr spanPtr C.envoy_dynamic_module_type_span_envoy_ptr @@ -501,88 +497,21 @@ func (s *dymSpan) SpawnChild(operation string) shared.ChildSpan { return nil } child := &dymChildSpan{ - childPtr: childPtr, - hostPluginPtr: s.hostPluginPtr, - filter: s.filter, + dymSpan: dymSpan{ + hostPluginPtr: s.hostPluginPtr, + spanPtr: C.envoy_dynamic_module_type_span_envoy_ptr(childPtr), + filter: s.filter, + }, + childPtr: childPtr, } s.filter.trackChildSpan(child) return child } -// dymChildSpan implements shared.ChildSpan. The module owns the underlying span and should -// call Finish exactly once; the filter destroy hook finishes any spans the module forgot. type dymChildSpan struct { - childPtr C.envoy_dynamic_module_type_child_span_module_ptr - hostPluginPtr C.envoy_dynamic_module_type_http_filter_envoy_ptr - filter *dymHttpFilterHandle - finished bool -} - -func (c *dymChildSpan) asSpanPtr() C.envoy_dynamic_module_type_span_envoy_ptr { - return C.envoy_dynamic_module_type_span_envoy_ptr(c.childPtr) -} - -func (c *dymChildSpan) SetTag(key, value string) { - C.envoy_dynamic_module_callback_http_span_set_tag( - c.asSpanPtr(), - stringToModuleBuffer(key), - stringToModuleBuffer(value), - ) - runtime.KeepAlive(key) - runtime.KeepAlive(value) -} - -func (c *dymChildSpan) SetOperation(operation string) { - C.envoy_dynamic_module_callback_http_span_set_operation( - c.asSpanPtr(), - stringToModuleBuffer(operation), - ) - runtime.KeepAlive(operation) -} - -func (c *dymChildSpan) Log(event string) { - C.envoy_dynamic_module_callback_http_span_log( - c.hostPluginPtr, - c.asSpanPtr(), - stringToModuleBuffer(event), - ) - runtime.KeepAlive(event) -} - -func (c *dymChildSpan) SetSampled(sampled bool) { - C.envoy_dynamic_module_callback_http_span_set_sampled( - c.asSpanPtr(), - (C.bool)(sampled), - ) -} - -func (c *dymChildSpan) SetBaggage(key, value string) { - C.envoy_dynamic_module_callback_http_span_set_baggage( - c.asSpanPtr(), - stringToModuleBuffer(key), - stringToModuleBuffer(value), - ) - runtime.KeepAlive(key) - runtime.KeepAlive(value) -} - -func (c *dymChildSpan) SpawnChild(operationName string) shared.ChildSpan { - childPtr := C.envoy_dynamic_module_callback_http_span_spawn_child( - c.hostPluginPtr, - c.asSpanPtr(), - stringToModuleBuffer(operationName), - ) - runtime.KeepAlive(operationName) - if childPtr == nil { - return nil - } - child := &dymChildSpan{ - childPtr: childPtr, - hostPluginPtr: c.hostPluginPtr, - filter: c.filter, - } - c.filter.trackChildSpan(child) - return child + dymSpan + childPtr C.envoy_dynamic_module_type_child_span_module_ptr + finished bool } func (c *dymChildSpan) Finish() { @@ -618,10 +547,6 @@ type dymHttpFilterHandle struct { downstreamWatermarkCallbacks shared.DownstreamWatermarkCallbacks - // childSpans tracks unfinished child spans owned by user code so the stream-destroy hook - // can finish any the module forgot. The host's span pointer stays valid until - // envoy_dynamic_module_callback_http_child_span_finish runs, so finishing orphans here - // is what releases the host-side Tracing::Span — dropping them would leak it. childSpans map[*dymChildSpan]struct{} } diff --git a/source/extensions/dynamic_modules/sdk/go/shared/http_api.go b/source/extensions/dynamic_modules/sdk/go/shared/api.go similarity index 82% rename from source/extensions/dynamic_modules/sdk/go/shared/http_api.go rename to source/extensions/dynamic_modules/sdk/go/shared/api.go index 301acefd6b9b2..209d6ab702f16 100644 --- a/source/extensions/dynamic_modules/sdk/go/shared/http_api.go +++ b/source/extensions/dynamic_modules/sdk/go/shared/api.go @@ -1,4 +1,4 @@ -//go:generate mockgen -source=http_api.go -destination=mocks/mock_http_api.go -package=mocks +//go:generate mockgen -source=api.go -destination=mocks/mock_api.go -package=mocks package shared type HeadersStatus int32 @@ -65,8 +65,6 @@ const ( TrailersStatusDefault TrailersStatus = TrailersStatusContinue ) -// LocalReplyStatus is returned from HttpFilter.OnLocalReply to control whether Envoy should -// send the local reply to the client or reset the stream instead. type LocalReplyStatus int32 const ( @@ -83,28 +81,38 @@ const ( // not implement flexible stream control. But it should be enough for most of the use cases. type HttpFilter interface { // OnRequestHeaders will be called when the request headers are received. - // Returns the status to control the plugin chain processing. + // @Param headers the request headers. + // @Param endOfStream whether this is the end of the stream. + // @Return HeadersStatus the status to control the plugin chain processing. OnRequestHeaders(headers HeaderMap, endOfStream bool) HeadersStatus // OnRequestBody will be called when the request body are received. This may be called multiple times. - // Returns the status to control the plugin chain processing. + // @Param body the request body. + // @Param endOfStream whether this is the end of the stream. + // @Return BodyStatus the status to control the plugin chain processing. OnRequestBody(body BodyBuffer, endOfStream bool) BodyStatus // OnRequestTrailers will be called when the request trailers are received. - // Returns the status to control the plugin chain processing. + // @Param trailers the request trailers. + // @Return TrailersStatus the status to control the plugin chain processing. OnRequestTrailers(trailers HeaderMap) TrailersStatus // OnResponseHeaders will be called when the response headers are received. - // Returns the status to control the plugin chain processing. + // @Param headers the response headers. + // @Param endOfStream whether this is the end of the stream. + // @Return HeadersStatus the status to control the plugin chain processing. OnResponseHeaders(headers HeaderMap, endOfStream bool) HeadersStatus // OnResponseBody will be called when the response body is received. This may be called multiple // times. - // Returns the status to control the plugin chain processing. + // @Param body the response body. + // @Param endOfStream whether this is the end of the stream. + // @Return BodyStatus the status to control the plugin chain processing. OnResponseBody(body BodyBuffer, endOfStream bool) BodyStatus // OnResponseTrailers will be called when the response trailers are received. - // Returns the status to control the plugin chain processing. + // @Param trailers the response trailers. + // @Return TrailersStatus the status to control the plugin chain processing. OnResponseTrailers(trailers HeaderMap) TrailersStatus // OnStreamComplete is called when the stream processing is complete and before access logs @@ -118,15 +126,16 @@ type HttpFilter interface { // any per-stream resources. OnDestroy() - // OnLocalReply is called when a local reply is being sent. The filter can either let the - // reply proceed (LocalReplyStatusContinue) or ask Envoy to reset the stream instead - // (LocalReplyStatusContinueAndResetStream). This is invoked before the reply leaves - // Envoy and before any stream reset. - // - // details is a short description of why the local reply is being sent (e.g. - // "buffer overflow", "rate limit exceeded"). The buffer aliases Envoy memory; copy - // before retaining past this call. resetImminent is true if Envoy is going to reset - // the stream after this call. + // OnLocalReply is called when a local reply is being sent. This allows the filter to modify + // the local reply or decide to reset the stream instead. This is called before the local reply + // is sent to the client and before the stream is reset. + // @Param responseCode the response code of the local reply. + // @Param details the details of the local reply. This is usually used to indicate the reason + // for sending the local reply, for example, "buffer overflow" or "rate limit exceeded". + // @Param resetImminent whether the stream is going to be reset after this local reply. This allows + // the filter to decide whether to continue with sending the local reply or just reset the stream. + // @Return LocalReplyStatus the status to control whether to continue with sending the local reply + // or reset the stream. OnLocalReply(responseCode uint32, details UnsafeEnvoyBuffer, resetImminent bool) LocalReplyStatus } diff --git a/source/extensions/dynamic_modules/sdk/go/shared/base.go b/source/extensions/dynamic_modules/sdk/go/shared/base.go new file mode 100644 index 0000000000000..a0f586f7d72d5 --- /dev/null +++ b/source/extensions/dynamic_modules/sdk/go/shared/base.go @@ -0,0 +1,873 @@ +//go:generate mockgen -source=base.go -destination=mocks/mock_base.go -package=mocks +package shared + +import ( + "strings" + "unsafe" +) + +// UnsafeEnvoyBuffer is a struct that represents a buffer of data from Envoy. +// It contains a pointer to the data and its length. The memory of the data is managed by Envoy. +type UnsafeEnvoyBuffer struct { + // Pointer to the start of the buffer data. + Ptr *byte + // Length of the buffer data in bytes. + Len uint64 +} + +func (b UnsafeEnvoyBuffer) ToUnsafeBytes() []byte { + if b.Ptr == nil || b.Len == 0 { + return nil + } + // Use unsafe to create a byte slice that points to the buffer data without copying. + return unsafe.Slice(b.Ptr, b.Len) +} + +// ToBytes converts the UnsafeEnvoyBuffer to a byte slice. It creates a copy of the data in Go memory. +func (b UnsafeEnvoyBuffer) ToBytes() []byte { + if b.Ptr == nil || b.Len == 0 { + return nil + } + // Create a byte slice that copys the data from the buffer. + owned := make([]byte, b.Len) + // Use unsafe to copy the data from the buffer to the byte slice. + src := unsafe.Slice(b.Ptr, b.Len) + copy(owned, src) + return owned +} + +func (b UnsafeEnvoyBuffer) ToUnsafeString() string { + if b.Ptr == nil || b.Len == 0 { + return "" + } + // Use unsafe to create a string that points to the buffer data without copying. + return unsafe.String(b.Ptr, b.Len) +} + +func (b UnsafeEnvoyBuffer) ToString() string { + if b.Ptr == nil || b.Len == 0 { + return "" + } + return strings.Clone(b.ToUnsafeString()) +} + +// BodyBuffer is an interface that provides access to the request and response body. +// This should be implemented by the SDK or runtime. +type BodyBuffer interface { + // GetChunks retrieves the body content as a list of UnsafeEnvoyBuffer chunks. + // NOTE: The memory of underlying data may not be managed by Go GC. So you should + // copy the data if you need to keep it and use it later. + GetChunks() []UnsafeEnvoyBuffer + + // GetSize retrieves the total size of the body buffer. + GetSize() uint64 + + // Drain removes the specified number of bytes from the beginning of the body buffer. + // @Param numBytes the number of bytes to drain. + Drain(numBytes uint64) + + // Append adds the specified bytes to the end of the body buffer. + // @Param data the bytes to append. + Append(data []byte) +} + +// HeaderMap is an interface that provides access to the request and response headers. +// This should be implemented by the SDK or runtime. +type HeaderMap interface { + // Get retrieves the header values for a given key. If the key does not exist, + // nil will be returned. + // NOTE: The memory of underlying data may not be managed by Go GC. So you should + // copy the data if you need to keep it and use it later. + Get(key string) []UnsafeEnvoyBuffer + + // GetOne retrieves a single header value for a given key. + // If there are multiple values for the key, the first one will be returned. + // If the key does not exist, an empty UnsafeEnvoyBuffer will be returned. + // NOTE: The memory of underlying data may not be managed by Go GC. So you should + // copy the data if you need to keep it and use it later. + GetOne(key string) UnsafeEnvoyBuffer + + // GetAll retrieves all header values. You should not mutate the returned slice + // directly. + // NOTE: The memory of underlying data may not be managed by Go GC. So you should + // copy the data if you need to keep it and use it later. + GetAll() [][2]UnsafeEnvoyBuffer + + // Set sets the header value for a given key. + Set(key string, value string) + + // Add adds a single header value for a given key. + Add(key string, value string) + + // Remove removes the header values for a given key. + Remove(key string) +} + +type AttributeID uint32 + +const ( + // request.path + AttributeIDRequestPath AttributeID = iota + // request.url_path + AttributeIDRequestUrlPath + // request.host + AttributeIDRequestHost + // request.scheme + AttributeIDRequestScheme + // request.method + AttributeIDRequestMethod + // request.headers + AttributeIDRequestHeaders + // request.referer + AttributeIDRequestReferer + // request.useragent + AttributeIDRequestUserAgent + // request.time + AttributeIDRequestTime + // request.id + AttributeIDRequestId + // request.protocol + AttributeIDRequestProtocol + // request.query + AttributeIDRequestQuery + // request.duration + AttributeIDRequestDuration + // request.size + AttributeIDRequestSize + // request.total_size + AttributeIDRequestTotalSize + // response.code + AttributeIDResponseCode + // response.code_details + AttributeIDResponseCodeDetails + // response.flags + AttributeIDResponseFlags + // response.grpc_status + AttributeIDResponseGrpcStatus + // response.headers + AttributeIDResponseHeaders + // response.trailers + AttributeIDResponseTrailers + // response.size + AttributeIDResponseSize + // response.total_size + AttributeIDResponseTotalSize + // response.backend_latency + AttributeIDResponseBackendLatency + // source.address + AttributeIDSourceAddress + // source.port + AttributeIDSourcePort + // destination.address + AttributeIDDestinationAddress + // destination.port + AttributeIDDestinationPort + // connection.id + AttributeIDConnectionId + // connection.mtls + AttributeIDConnectionMtls + // connection.requested_server_name + AttributeIDConnectionRequestedServerName + // connection.tls_version + AttributeIDConnectionTlsVersion + // connection.subject_local_certificate + AttributeIDConnectionSubjectLocalCertificate + // connection.subject_peer_certificate + AttributeIDConnectionSubjectPeerCertificate + // connection.dns_san_local_certificate + AttributeIDConnectionDnsSanLocalCertificate + // connection.dns_san_peer_certificate + AttributeIDConnectionDnsSanPeerCertificate + // connection.uri_san_local_certificate + AttributeIDConnectionUriSanLocalCertificate + // connection.uri_san_peer_certificate + AttributeIDConnectionUriSanPeerCertificate + // connection.sha256_peer_certificate_digest + AttributeIDConnectionSha256PeerCertificateDigest + // connection.transport_failure_reason + AttributeIDConnectionTransportFailureReason + // connection.termination_details + AttributeIDConnectionTerminationDetails + // upstream.address + AttributeIDUpstreamAddress + // upstream.port + AttributeIDUpstreamPort + // upstream.tls_version + AttributeIDUpstreamTlsVersion + // upstream.subject_local_certificate + AttributeIDUpstreamSubjectLocalCertificate + // upstream.subject_peer_certificate + AttributeIDUpstreamSubjectPeerCertificate + // upstream.dns_san_local_certificate + AttributeIDUpstreamDnsSanLocalCertificate + // upstream.dns_san_peer_certificate + AttributeIDUpstreamDnsSanPeerCertificate + // upstream.uri_san_local_certificate + AttributeIDUpstreamUriSanLocalCertificate + // upstream.uri_san_peer_certificate + AttributeIDUpstreamUriSanPeerCertificate + // upstream.sha256_peer_certificate_digest + AttributeIDUpstreamSha256PeerCertificateDigest + // upstream.local_address + AttributeIDUpstreamLocalAddress + // upstream.transport_failure_reason + AttributeIDUpstreamTransportFailureReason + // upstream.request_attempt_count + AttributeIDUpstreamRequestAttemptCount + // upstream.cx_pool_ready_duration + AttributeIDUpstreamCxPoolReadyDuration + // upstream.locality + AttributeIDUpstreamLocality + // xds.node + AttributeIDXdsNode + // xds.cluster_name + AttributeIDXdsClusterName + // xds.cluster_metadata + AttributeIDXdsClusterMetadata + // xds.listener_direction + AttributeIDXdsListenerDirection + // xds.listener_metadata + AttributeIDXdsListenerMetadata + // xds.route_name + AttributeIDXdsRouteName + // xds.route_metadata + AttributeIDXdsRouteMetadata + // xds.virtual_host_name + AttributeIDXdsVirtualHostName + // xds.virtual_host_metadata + AttributeIDXdsVirtualHostMetadata + // xds.upstream_host_metadata + AttributeIDXdsUpstreamHostMetadata + // xds.filter_chain_name + AttributeIDXdsFilterChainName + // health_check + AttributeIDHealthCheck +) + +type LogLevel uint32 + +const ( + LogLevelTrace LogLevel = iota + LogLevelDebug + LogLevelInfo + LogLevelWarn + LogLevelError + LogLevelCritical + LogLevelOff +) + +type HttpCalloutInitResult uint32 + +const ( + HttpCalloutInitSuccess HttpCalloutInitResult = iota + HttpCalloutInitMissingRequiredHeaders + HttpCalloutInitClusterNotFound + HttpCalloutInitDuplicateCalloutId + HttpCalloutInitCannotCreateRequest +) + +type HttpCalloutResult uint32 + +const ( + HttpCalloutSuccess HttpCalloutResult = iota + HttpCalloutReset + HttpCalloutExceedResponseBufferLimit +) + +type MetadataSourceType uint32 + +const ( + MetadataSourceTypeDynamic MetadataSourceType = iota + MetadataSourceTypeRoute + MetadataSourceTypeCluster + MetadataSourceTypeHost + MetadataSourceTypeHostLocality +) + +type HttpCalloutCallback interface { + OnHttpCalloutDone(calloutID uint64, result HttpCalloutResult, + headers [][2]UnsafeEnvoyBuffer, body []UnsafeEnvoyBuffer) +} + +type HttpStreamResetReason uint32 + +const ( + HttpStreamResetReasonConnectionFailure = iota + HttpStreamResetReasonConnectionTermination + HttpStreamResetReasonLocalReset + HttpStreamResetReasonLocalRefusedStreamReset + HttpStreamResetReasonOverflow + HttpStreamResetReasonRemoteReset + HttpStreamResetReasonRemoteRefusedStreamReset + HttpStreamResetReasonProtocolError +) + +type HttpStreamCallback interface { + OnHttpStreamHeaders(streamID uint64, headers [][2]UnsafeEnvoyBuffer, endStream bool) + OnHttpStreamData(streamID uint64, body []UnsafeEnvoyBuffer, endStream bool) + OnHttpStreamTrailers(streamID uint64, trailers [][2]UnsafeEnvoyBuffer) + OnHttpStreamComplete(streamID uint64) + OnHttpStreamReset(streamID uint64, reason HttpStreamResetReason) +} + +// Scheduler is the interface that provides scheduling capabilities for asynchronous operations. +// This allow the plugins run tasks in another thread and continue the processing later at the +// thread where the stream plugin is being processed. +type Scheduler interface { + // Schedule schedules a function to be executed asynchronously in the thread where the stream + // plugin is being processed. + // @Param func the function to be executed. + // NOTE: This function may be ignored if the related plugin processing is completed. + Schedule(func()) +} + +type DownstreamWatermarkCallbacks interface { + OnAboveWriteBufferHighWatermark() + OnBelowWriteBufferLowWatermark() +} + +type HttpFilterStreamResetReason uint32 + +const ( + HttpFilterStreamResetReasonLocalReset HttpFilterStreamResetReason = iota + HttpFilterStreamResetReasonLocalRefusedStreamReset +) + +type SocketOptionState uint32 + +const ( + SocketOptionStatePrebind SocketOptionState = iota + SocketOptionStateBound + SocketOptionStateListening +) + +type SocketDirection uint32 + +const ( + SocketDirectionUpstream SocketDirection = iota + SocketDirectionDownstream +) + +type ClusterHostCounts struct { + Total uint64 + Healthy uint64 + Degraded uint64 +} + +type Span interface { + SetTag(key, value string) + SetOperation(operation string) + Log(event string) + SetSampled(sampled bool) + GetBaggage(key string) (UnsafeEnvoyBuffer, bool) + SetBaggage(key, value string) + GetTraceID() (UnsafeEnvoyBuffer, bool) + GetSpanID() (UnsafeEnvoyBuffer, bool) + SpawnChild(operation string) ChildSpan +} + +type ChildSpan interface { + Span + Finish() +} + +// HttpFilterHandle is the interface that provides access to the plugin's context and configuration. +// This should be implemented by the SDK or runtime. +type HttpFilterHandle interface { + // GetMetadataString retrieves the dynamic metadata string value of the stream. + // @Param source the metadata source type. + // @Param metadataNamespace the metadata namespace. + // @Param key the metadata key. + // @Return the metadata value if found, otherwise an empty UnsafeEnvoyBuffer. + GetMetadataString(source MetadataSourceType, metadataNamespace, key string) (UnsafeEnvoyBuffer, bool) + + // GetMetadataNumber retrieves the dynamic metadata number value of the stream. + // @Param source the metadata source type. + // @Param metadataNamespace the metadata namespace. + // @Param key the metadata key. + // @Return the metadata value if found, otherwise nil. + GetMetadataNumber(source MetadataSourceType, metadataNamespace, key string) (float64, bool) + + // GetMetadataBool retrieves the dynamic metadata bool value of the stream. + // @Param source the metadata source type. + // @Param metadataNamespace the metadata namespace. + // @Param key the metadata key. + // @Return the metadata value and true if found, otherwise false. + GetMetadataBool(source MetadataSourceType, metadataNamespace, key string) (bool, bool) + + // SetMetadata sets the dynamic metadata value of the stream. + // @Param metadataNamespace the metadata namespace. + // @Param key the metadata key. + // @Param value the metadata value. Only string/int/float/bool are supported. + SetMetadata(metadataNamespace, key string, value any) + + // GetMetadataKeys retrieves all keys in the given metadata namespace. + // @Param source the metadata source type. + // @Param metadataNamespace the metadata namespace. + // @Return the list of keys in the namespace, or nil if the namespace does not exist. + // NOTE: The memory of underlying data may not be managed by Go GC. So you should + // copy the data if you need to keep it and use it later. + GetMetadataKeys(source MetadataSourceType, metadataNamespace string) []UnsafeEnvoyBuffer + + // GetMetadataNamespaces retrieves all namespace names in the metadata. + // @Param source the metadata source type. + // @Return the list of namespace names, or nil if no namespaces exist. + // NOTE: The memory of underlying data may not be managed by Go GC. So you should + // copy the data if you need to keep it and use it later. + GetMetadataNamespaces(source MetadataSourceType) []UnsafeEnvoyBuffer + + // AddMetadataListNumber appends a number value to the dynamic metadata list stored under the + // given namespace and key. If the key does not exist, a new list is created. Returns false if + // the key exists but is not a list, or if the metadata is not accessible. + AddMetadataListNumber(metadataNamespace, key string, value float64) bool + + // AddMetadataListString appends a string value to the dynamic metadata list stored under the + // given namespace and key. If the key does not exist, a new list is created. Returns false if + // the key exists but is not a list, or if the metadata is not accessible. + AddMetadataListString(metadataNamespace, key string, value string) bool + + // AddMetadataListBool appends a bool value to the dynamic metadata list stored under the + // given namespace and key. If the key does not exist, a new list is created. Returns false if + // the key exists but is not a list, or if the metadata is not accessible. + AddMetadataListBool(metadataNamespace, key string, value bool) bool + + // GetMetadataListSize returns the number of elements in the metadata list stored under the + // given namespace and key. Returns (0, false) if the metadata is not accessible, the namespace + // or key does not exist, or the value is not a list. + GetMetadataListSize(source MetadataSourceType, metadataNamespace, key string) (int, bool) + + // GetMetadataListNumber returns the number element at the given index in the metadata list + // stored under the given namespace and key. Returns (0, false) if the metadata is not + // accessible, the namespace or key does not exist, the value is not a list, the index is out + // of range, or the element is not a number. + GetMetadataListNumber(source MetadataSourceType, metadataNamespace, key string, index int) (float64, bool) + + // GetMetadataListString returns the string element at the given index in the metadata list + // stored under the given namespace and key. Returns an empty buffer and false if the metadata is + // not accessible, the namespace or key does not exist, the value is not a list, the index is + // out of range, or the element is not a string. + // NOTE: The memory of underlying data may not be managed by Go GC. So you should + // copy the data if you need to keep it and use it later. + GetMetadataListString(source MetadataSourceType, metadataNamespace, key string, index int) (UnsafeEnvoyBuffer, bool) + + // GetMetadataListBool returns the bool element at the given index in the metadata list stored + // under the given namespace and key. Returns (false, false) if the metadata is not accessible, + // the namespace or key does not exist, the value is not a list, the index is out of range, or + // the element is not a bool. + GetMetadataListBool(source MetadataSourceType, metadataNamespace, key string, index int) (bool, bool) + + // GetFilterState retrieves the serialized filter state value of the stream. + // @Param key the filter state key. + // @Return the filter state value if found, otherwise an empty UnsafeEnvoyBuffer. + // NOTE: The memory of underlying data may not be managed by Go GC. So you should + // copy the data if you need to keep it and use it later. + GetFilterState(key string) (UnsafeEnvoyBuffer, bool) + + // SetFilterState sets the serialized filter state value of the stream. + // @Param key the filter state key. + // @Param value the filter state value. + SetFilterState(key string, value []byte) + + // SetFilterStateTyped sets a typed filter state object from serialized bytes using the registered + // Envoy ObjectFactory for the given key. + // @Param key the filter state key. + // @Param value the serialized bytes used to construct the typed object. + // @Return true if the value was stored successfully, otherwise false. + SetFilterStateTyped(key string, value []byte) bool + + // GetAttributeString retrieves the string attribute value of the stream. + // @Param attributeID the attribute ID. + // @Return the attribute value if found, otherwise an empty UnsafeEnvoyBuffer. + // NOTE: The memory of underlying data may not be managed by Go GC. So you should + // copy the data if you need to keep it and use it later. + GetAttributeString(attributeID AttributeID) (UnsafeEnvoyBuffer, bool) + + // GetAttributeNumber retrieves the uint64 attribute value of the stream. + // @Param key the attribute key. + // @Return the attribute value if found, otherwise nil. + GetAttributeNumber(attributeID AttributeID) (uint64, bool) + + // GetAttributeBool retrieves the bool attribute value of the stream. + // @Param attributeID the attribute ID. + // @Return the attribute value and true if found, otherwise false. + GetAttributeBool(attributeID AttributeID) (bool, bool) + + // GetFilterStateTyped retrieves the serialized value of a typed filter state object. + // @Param key the filter state key. + // @Return the serialized value if found, otherwise an empty UnsafeEnvoyBuffer. + GetFilterStateTyped(key string) (UnsafeEnvoyBuffer, bool) + + // GetData retrieves internal data stored for cross-phase communication. + // This data is not included in DynamicMetadata responses. + // @Param key the data key. + // @Return the data value if found, otherwise nil. + GetData(key string) any + + // SetData sets internal data for cross-phase communication. + // This data is not included in DynamicMetadata responses. + // @Param key the data key. + // @Param value the data value. + SetData(key string, value any) + + // SendLocalResponse sends a local reply to the client and terminates the stream. + // @Param status the HTTP status code. + // @Param headers the response headers. + // @Param body the response body. + // @Param detail a short description to the response for debugging purposes. + SendLocalResponse(status uint32, headers [][2]string, body []byte, detail string) + + // SendResponseHeaders sends response headers to the client. This is used for + // streaming local replies. + // + // @Param headers the response headers. + // @Param endOfStream whether this is the end of the stream. + SendResponseHeaders(headers [][2]string, endOfStream bool) + + // SendResponseData sends response body data to the client. This is used for + // streaming local replies. + // + // @Param body the response body data. + // @Param endOfStream whether this is the end of the stream. + SendResponseData(body []byte, endOfStream bool) + + // SendResponseTrailers sends response trailers to the client. This is used for + // streaming local replies. + // + // @Param trailers the response trailers. + SendResponseTrailers(trailers [][2]string) + + // AddCustomFlag adds a custom flag to the stream. This flag should be very short + // string to indicate some custom state or information of the stream. + // @Param flag the custom flag to add. + AddCustomFlag(flag string) + + // ContinueRequest continues the request stream processing. + // NOTE: This function should only be called when the plugin chains are hung up because + // of asynchronous operations. + ContinueRequest() + + // ContinueResponse continues the response stream processing. + // NOTE: This function should only be called when the plugin chains are hung up because + // of asynchronous operations. + ContinueResponse() + + // ClearRouteCache clears the cached route for the stream. + ClearRouteCache() + + // RefreshRouteCluster clears only the cluster selection for the current route without + // clearing the entire route cache. + // This is a subset of ClearRouteCache. Use this when a filter modifies headers that affect + // cluster selection but not the route itself. + RefreshRouteCluster() + + // GetWorkerIndex returns the worker index assigned to the current filter instance. + GetWorkerIndex() uint32 + + // SetSocketOptionInt sets an integer socket option on the upstream or downstream connection. + SetSocketOptionInt(level, name int64, state SocketOptionState, direction SocketDirection, value int64) bool + + // SetSocketOptionBytes sets a bytes socket option on the upstream or downstream connection. + SetSocketOptionBytes(level, name int64, state SocketOptionState, direction SocketDirection, value []byte) bool + + // GetSocketOptionInt retrieves an integer socket option from the upstream or downstream connection. + GetSocketOptionInt(level, name int64, state SocketOptionState, direction SocketDirection) (int64, bool) + + // GetSocketOptionBytes retrieves a bytes socket option from the upstream or downstream connection. + GetSocketOptionBytes(level, name int64, state SocketOptionState, direction SocketDirection) (UnsafeEnvoyBuffer, bool) + + // GetBufferLimit returns the current body buffering limit in bytes. + GetBufferLimit() uint64 + + // SetBufferLimit sets the current body buffering limit in bytes. + SetBufferLimit(limit uint64) + + // GetActiveSpan retrieves the active tracing span for the stream. + GetActiveSpan() Span + + // GetClusterName retrieves the selected upstream cluster name for the stream. + GetClusterName() (UnsafeEnvoyBuffer, bool) + + // GetClusterHostCounts retrieves the total, healthy, and degraded host counts for the selected + // cluster at the given priority. + GetClusterHostCounts(priority uint32) (ClusterHostCounts, bool) + + // SetUpstreamOverrideHost sets an override host for the selected upstream cluster. + SetUpstreamOverrideHost(host string, strict bool) bool + + // ResetStream resets the downstream HTTP stream with the given reason and details string. + ResetStream(reason HttpFilterStreamResetReason, details string) + + // SendGoAwayAndClose sends a GOAWAY frame to the downstream and closes the connection. + SendGoAwayAndClose(graceful bool) + + // RecreateStream recreates the HTTP stream, optionally with replacement headers. + RecreateStream(headers [][2]string) bool + + // RequestHeaders retrieves the request headers. + // @Return the request headers. + RequestHeaders() HeaderMap + + // BufferedRequestBody retrieves the buffered request body in the chain. + // NOTE: Different with the headers and trailers, because of the streaming processing, + // the request body is not always fully buffered. So this function only retrieves the + // currently buffered body in the chain. And the latest newly received body chunk is passed + // as the parameter to OnRequestBody. Only when endOfStream is true or OnRequestTrailers is + // called, the full request body is received. + // @Return the buffered request body. + BufferedRequestBody() BodyBuffer + + // ReceivedRequestBody retrieves the latest received request body chunk in the OnRequestBody callback. + // NOTE: This is only valid in the OnRequestBody callback, and it retrieves the latest received + // body chunk that triggers the callback. For other callbacks or outside of the callbacks, you + // should use BufferedRequestBody to get the currently buffered body in the chain. + ReceivedRequestBody() BodyBuffer + + // RequestTrailers retrieves the request trailers. + // @Return the request trailers. + RequestTrailers() HeaderMap + + // ResponseHeaders retrieves the response headers. + // @Return the response headers. + ResponseHeaders() HeaderMap + + // BufferedResponseBody retrieves the buffered response body in the chain. + // NOTE: Different with the headers and trailers, because of the streaming processing, + // the request body is not always fully buffered. So this function only retrieves the + // currently buffered body in the chain. And the latest newly received body chunk is passed + // as the parameter to OnResponseBody. Only when endOfStream is true or OnResponseTrailers is + // called, the full request body is received. + // @Return the buffered response body. + BufferedResponseBody() BodyBuffer + + // ReceivedResponseBody retrieves the latest received response body chunk in the OnResponseBody callback. + // NOTE: This is only valid in the OnResponseBody callback, and it retrieves the latest received + // body chunk that triggers the callback. For other callbacks or outside of the callbacks, you + // should use BufferedResponseBody to get the currently buffered body in the chain. + ReceivedResponseBody() BodyBuffer + + // ReceivedBufferedRequestBody returns true if the latest received request body is the + // previously buffered request body. This is true when a previous filter in the chain stopped + // and buffered the request body, then resumed, and this filter is now receiving that buffered + // body. + // NOTE: This is only meaningful inside the OnRequestBody callback. + ReceivedBufferedRequestBody() bool + + // ReceivedBufferedResponseBody returns true if the latest received response body is the + // previously buffered response body. This is true when a previous filter in the chain stopped + // and buffered the response body, then resumed, and this filter is now receiving that buffered + // body. + // NOTE: This is only meaningful inside the OnResponseBody callback. + ReceivedBufferedResponseBody() bool + + // ResponseTrailers retrieves the response trailers. + // @Return the response trailers. + ResponseTrailers() HeaderMap + + // GetMostSpecificConfig retrieves the most specific route configuration for the stream. + GetMostSpecificConfig() any + + // GetScheduler retrieves the scheduler related to this stream plugin for asynchronous + // operations. + // + // NOTE: This MUST only be called during OnRequest* or OnResponse* callbacks. But then the + // returned Scheduler can be used later even outside of the callbacks and even at other + // threads. + GetScheduler() Scheduler + + // Log will log the given message via the host environment's logging mechanism. + Log(level LogLevel, format string, args ...any) + + // HttpCallout performs an HTTP call to an external service. The call is asynchronous, and the + // response will be delivered via the provided callback. + // @Param cluster the cluster (target) name to which the HTTP call will be made. + // @Param headers the HTTP headers to be sent with the request. + // @Param body the HTTP body to be sent with the request. + // @Param timeoutMs the timeout in milliseconds for the HTTP call. + // @Param callback the callback function to be invoked when the response is received or an + // error occurs. + // The callback function receives the response headers, body, and an error if any occurred. + // + // @Return the result of the HTTP callout initialization and the callout ID. Non-success results + // indicate that the callout failed to start. + // + // NOTE: This method should only be called during OnRequest* or OnResponse* callbacks or + // scheduled functions via the Scheduler. By this way we can ensure this is only be called + // in the thread where the stream plugin is being processed. + HttpCallout(cluster string, headers [][2]string, body []byte, timeoutMs uint64, + cb HttpCalloutCallback) (HttpCalloutInitResult, uint64) + + // StartHttpStream starts a new HTTP stream to an external service. The stream is asynchronous, + // and the response will be delivered via the provided callback. + // @Param cluster the cluster (target) name to which the HTTP stream will be made. + // @Param headers the initial HTTP headers to be sent with the request. + // @Param body the initial HTTP body to be sent with the request. + // @Param endOfStream whether this is the end of the stream. + // @Param timeoutMs the timeout in milliseconds for the HTTP stream. + // @Param callback the callback interface to handle the stream events. + // + // @Return the result of the HTTP stream initialization and the stream ID. Non-success results + // indicate that the stream failed to start. + // + // NOTE: This method should only be called during OnRequest* or OnResponse* callbacks or + // scheduled functions via the Scheduler. By this way we can ensure this is only be called + // in the thread where the stream plugin is being processed. + StartHttpStream(cluster string, headers [][2]string, body []byte, endOfStream bool, timeoutMs uint64, + cb HttpStreamCallback) (HttpCalloutInitResult, uint64) + + // SendHttpStreamData sends data on an existing HTTP stream. + // @Param streamID the ID of the HTTP stream. + // @Param body the HTTP body to be sent with the request. + // @Param endOfStream whether this is the end of the stream. + // + // @Return whether the data was successfully sent. + // + // NOTE: This method should only be called during OnRequest* or OnResponse* callbacks or + // scheduled functions via the Scheduler. By this way we can ensure this is only be called + // in the thread where the stream plugin is being processed. + SendHttpStreamData(streamID uint64, body []byte, endOfStream bool) bool + + // SendHttpStreamTrailers sends trailers on an existing HTTP stream. + // @Param streamID the ID of the HTTP stream. + // @Param trailers the HTTP trailers to be sent with the request. + // + // @Return whether the trailers were successfully sent. + // + // NOTE: This method should only be called during OnRequest* or OnResponse* callbacks or + // scheduled functions via the Scheduler. By this way we can ensure this is only be called + // in the thread where the stream plugin is being processed. + SendHttpStreamTrailers(streamID uint64, trailers [][2]string) bool + + // ResetHttpStream resets an existing HTTP stream. + // @Param streamID the ID of the HTTP stream. + // + // NOTE: This method should only be called during OnRequest* or OnResponse* callbacks or + // scheduled functions via the Scheduler. By this way we can ensure this is only be called + // in the thread where the stream plugin is being processed. + ResetHttpStream(streamID uint64) + + // SetDownstreamWatermarkCallbacks sets the downstream watermark callbacks for the stream. + // @Param callbacks the downstream watermark callbacks. + SetDownstreamWatermarkCallbacks(callbacks DownstreamWatermarkCallbacks) + + // ClearDownstreamWatermarkCallbacks unsets the downstream watermark callbacks for the stream. + ClearDownstreamWatermarkCallbacks() + + // RecordValue records the given value to the histogram metric. + // @Param id the histogram metric id. + // @Param value the value to be recorded. + // @Param tagsValues the optional tag values associated with the metric. The order and size + // of the tag values must match the tag keys defined when the metric was created. + RecordHistogramValue(id MetricID, value uint64, tagsValues ...string) MetricsResult + + // SetValue sets the given value to the gauge metric. + // @Param id the gauge metric id. + // @Param value the value to be set. + // @Param tagsValues the optional tag values associated with the metric. The order and size + // of the tag values must match the tag keys defined when the metric was created. + SetGaugeValue(id MetricID, value uint64, tagsValues ...string) MetricsResult + + // IncrementGaugeValue adds the given value to the gauge metric. + // @Param id the gauge metric id. + // @Param value the value to be added. + // @Param tagsValues the optional tag values associated with the metric. The order and size + // of the tag values must match the tag keys defined when the metric was created. + IncrementGaugeValue(id MetricID, value uint64, tagsValues ...string) MetricsResult + + // DecrementGaugeValue subtracts the given value from the gauge metric. + // @Param id the gauge metric id. + // @Param value the value to be subtracted. + // @Param tagsValues the optional tag values associated with the metric. The order and size + // of the tag values must match the tag keys defined when the metric was created. + DecrementGaugeValue(id MetricID, value uint64, tagsValues ...string) MetricsResult + + // IncrementCounterValue adds the given value to the counter metric. + // @Param id the counter metric id. + // @Param value the value to be added. + // @Param tagsValues the optional tag values associated with the metric. The order and size + // of the tag values must match the tag keys defined when the metric was created. + IncrementCounterValue(id MetricID, value uint64, tagsValues ...string) MetricsResult +} + +type MetricID uint64 +type MetricsResult uint32 + +const ( + MetricsSuccess MetricsResult = iota + MetricsNotFound + MetricsInvalidTags + MetricsFrozen +) + +type HttpFilterConfigHandle interface { + // Log will log the given message via the host environment's logging mechanism. + Log(level LogLevel, format string, args ...any) + + // DefineHistogram creates a histogram metric with the given name, and tag keys. + // @Param name the name of the metric. + // @Param tagKeys the optional tag keys for the metric. + // @Return the histogram metric id. This metric can never be used after the plugin + // config is unloaded. + DefineHistogram(name string, tagKeys ...string) (MetricID, MetricsResult) + + // DefineGauge creates a gauge metric with the given name, description, and tag keys. + // @Param name the name of the metric. + // @Param tagKeys the optional tag keys for the metric. + // @Return the gauge metric id. This metric can never be used after the plugin + // config is unloaded. + DefineGauge(name string, tagKeys ...string) (MetricID, MetricsResult) + + // DefineCounter creates a counter metric with the given name, description, and tag keys. + // @Param name the name of the metric. + // @Param tagKeys the optional tag keys for the metric. + // @Return the counter metric id. This metric can never be used after the plugin + // config is unloaded. + DefineCounter(name string, tagKeys ...string) (MetricID, MetricsResult) + + // HttpCallout performs an HTTP call to an external service from the config context. + // The call is asynchronous, and the response will be delivered via the provided callback. + // This is similar to HttpFilterHandle.HttpCallout but runs on the main thread rather than + // the worker thread. + // @Param cluster the cluster (target) name to which the HTTP call will be made. + // @Param headers the HTTP headers to be sent with the request. + // @Param body the HTTP body to be sent with the request. + // @Param timeoutMs the timeout in milliseconds for the HTTP call. + // @Param callback the callback function to be invoked when the response is received. + // @Return the result of the HTTP callout initialization and the callout ID. + HttpCallout(cluster string, headers [][2]string, body []byte, timeoutMs uint64, + cb HttpCalloutCallback) (HttpCalloutInitResult, uint64) + + // StartHttpStream starts a new HTTP stream to an external service from the config context. + // The stream is asynchronous, and the response will be delivered via the provided callback. + // This is similar to HttpFilterHandle.StartHttpStream but runs on the main thread. + // @Param cluster the cluster (target) name. + // @Param headers the initial HTTP headers. + // @Param body the initial HTTP body. + // @Param endOfStream whether this is the end of the stream. + // @Param timeoutMs the timeout in milliseconds. + // @Param callback the callback interface to handle the stream events. + // @Return the result of the HTTP stream initialization and the stream ID. + StartHttpStream(cluster string, headers [][2]string, body []byte, endOfStream bool, + timeoutMs uint64, cb HttpStreamCallback) (HttpCalloutInitResult, uint64) + + // SendHttpStreamData sends data on an existing HTTP stream started via StartHttpStream. + // @Param streamID the ID of the HTTP stream. + // @Param body the HTTP body to be sent. + // @Param endOfStream whether this is the end of the stream. + // @Return whether the data was successfully sent. + SendHttpStreamData(streamID uint64, body []byte, endOfStream bool) bool + + // SendHttpStreamTrailers sends trailers on an existing HTTP stream started via StartHttpStream. + // @Param streamID the ID of the HTTP stream. + // @Param trailers the HTTP trailers to be sent. + // @Return whether the trailers were successfully sent. + SendHttpStreamTrailers(streamID uint64, trailers [][2]string) bool + + // ResetHttpStream resets an existing HTTP stream started via StartHttpStream. + // @Param streamID the ID of the HTTP stream. + ResetHttpStream(streamID uint64) + + // GetScheduler retrieves a scheduler for deferred task execution in the config context. + // This should be called only during the plugin configuration phase, and the returned + // Scheduler can be used later even outside of the callbacks and at other threads. + GetScheduler() Scheduler +} diff --git a/source/extensions/dynamic_modules/sdk/go/shared/fake/fake_http.go b/source/extensions/dynamic_modules/sdk/go/shared/fake/fake_stream_base.go similarity index 95% rename from source/extensions/dynamic_modules/sdk/go/shared/fake/fake_http.go rename to source/extensions/dynamic_modules/sdk/go/shared/fake/fake_stream_base.go index f642d361ee5ac..a6fee1eacd60f 100644 --- a/source/extensions/dynamic_modules/sdk/go/shared/fake/fake_http.go +++ b/source/extensions/dynamic_modules/sdk/go/shared/fake/fake_stream_base.go @@ -7,11 +7,6 @@ import ( "github.com/envoyproxy/envoy/source/extensions/dynamic_modules/sdk/go/shared" ) -var ( - _ shared.HeaderMap = (*FakeHeaderMap)(nil) - _ shared.BodyBuffer = (*FakeBodyBuffer)(nil) -) - type FakeHeaderMap struct { Headers map[string][]string } diff --git a/source/extensions/dynamic_modules/sdk/go/shared/fake/fake_http_test.go b/source/extensions/dynamic_modules/sdk/go/shared/fake/fake_stream_base_test.go similarity index 100% rename from source/extensions/dynamic_modules/sdk/go/shared/fake/fake_http_test.go rename to source/extensions/dynamic_modules/sdk/go/shared/fake/fake_stream_base_test.go diff --git a/source/extensions/dynamic_modules/sdk/go/shared/http.go b/source/extensions/dynamic_modules/sdk/go/shared/http.go deleted file mode 100644 index ffcfcda1d0de2..0000000000000 --- a/source/extensions/dynamic_modules/sdk/go/shared/http.go +++ /dev/null @@ -1,579 +0,0 @@ -//go:generate mockgen -source=http.go -destination=mocks/mock_http.go -package=mocks -package shared - -// HTTP filter SDK surface for dynamic modules — handle, buffer, header, span, and watermark -// types used by the user-facing interfaces in http_api.go. -// -// Cross-surface primitives (UnsafeEnvoyBuffer, LogLevel, MetricID, AttributeID, Scheduler, -// HttpCalloutInitResult/Result/Callback, HttpStreamCallback/ResetReason, SocketOption*, -// ClusterHostCounts, HttpHeaderType) live in types.go. - -// BodyBuffer is an interface that provides access to the request and response body. -// This should be implemented by the SDK or runtime. -type BodyBuffer interface { - // GetChunks retrieves the body content as a list of UnsafeEnvoyBuffer chunks. - // NOTE: The memory of underlying data may not be managed by Go GC. So you should - // copy the data if you need to keep it and use it later. - GetChunks() []UnsafeEnvoyBuffer - - // GetSize retrieves the total size of the body buffer. - GetSize() uint64 - - // Drain removes the specified number of bytes from the beginning of the body buffer. - Drain(numBytes uint64) - - // Append adds the specified bytes to the end of the body buffer. - Append(data []byte) -} - -// HeaderMap is an interface that provides access to the request and response headers. -// This should be implemented by the SDK or runtime. -type HeaderMap interface { - // Get retrieves the header values for a given key. If the key does not exist, - // nil will be returned. - // NOTE: The memory of underlying data may not be managed by Go GC. So you should - // copy the data if you need to keep it and use it later. - Get(key string) []UnsafeEnvoyBuffer - - // GetOne retrieves a single header value for a given key. - // If there are multiple values for the key, the first one will be returned. - // If the key does not exist, an empty UnsafeEnvoyBuffer will be returned. - // NOTE: The memory of underlying data may not be managed by Go GC. So you should - // copy the data if you need to keep it and use it later. - GetOne(key string) UnsafeEnvoyBuffer - - // GetAll retrieves all header values. You should not mutate the returned slice - // directly. - // NOTE: The memory of underlying data may not be managed by Go GC. So you should - // copy the data if you need to keep it and use it later. - GetAll() [][2]UnsafeEnvoyBuffer - - // Set sets the header value for a given key. - Set(key string, value string) - - // Add adds a single header value for a given key. - Add(key string, value string) - - // Remove removes the header values for a given key. - Remove(key string) -} - -// MetadataSourceType identifies which metadata source to read from. Corresponds to -// envoy_dynamic_module_type_metadata_source. -type MetadataSourceType uint32 - -const ( - MetadataSourceTypeDynamic MetadataSourceType = iota - MetadataSourceTypeRoute - MetadataSourceTypeCluster - MetadataSourceTypeHost - MetadataSourceTypeHostLocality -) - -// HttpFilterStreamResetReason is the reason for resetting the main HTTP stream via -// HttpFilterHandle.ResetStream. This corresponds to envoy_dynamic_module_type_http_filter_stream_reset_reason -// in the dynamic module ABI. -type HttpFilterStreamResetReason uint32 - -const ( - // HttpFilterStreamResetReasonLocalReset indicates a local codec level reset was sent on the stream. - HttpFilterStreamResetReasonLocalReset HttpFilterStreamResetReason = iota - // HttpFilterStreamResetReasonLocalRefusedStreamReset indicates a local codec level refused stream - // reset was sent on the stream (allowing for retry). - HttpFilterStreamResetReasonLocalRefusedStreamReset -) - -// Span is a tracing span associated with the current HTTP stream. It is owned by Envoy and is -// valid for the lifetime of the HTTP stream. Modules MUST NOT call Finish on the active span - -// it is managed by Envoy. Use SpawnChild to create child spans whose lifetime the module owns. -type Span interface { - // SetTag sets a key/value tag on the span. - SetTag(key, value string) - - // SetOperation sets the operation name on the span. - SetOperation(operation string) - - // Log records an event on the span with the current timestamp. - Log(event string) - - // SetSampled overrides the sampling decision for the span. If sampled is false, this span and - // any subsequent child spans will not be reported to the tracing system. - SetSampled(sampled bool) - - // GetBaggage retrieves a baggage value from the span. Returns the value and true if the key - // was found, otherwise an empty buffer and false. - // NOTE: The memory of the underlying data may not be managed by Go GC. Copy the data if you - // need to keep it past the current callback. - GetBaggage(key string) (UnsafeEnvoyBuffer, bool) - - // SetBaggage sets a baggage value on the span. All subsequent child spans will have access to - // this baggage. - SetBaggage(key, value string) - - // GetTraceID retrieves the trace ID from the span. Returns the value and true if available, - // otherwise an empty buffer and false. - // NOTE: The memory of the underlying data may not be managed by Go GC. Copy the data if you - // need to keep it past the current callback. - GetTraceID() (UnsafeEnvoyBuffer, bool) - - // GetSpanID retrieves the span ID from the span. Returns the value and true if available, - // otherwise an empty buffer and false. - // NOTE: The memory of the underlying data may not be managed by Go GC. Copy the data if you - // need to keep it past the current callback. - GetSpanID() (UnsafeEnvoyBuffer, bool) - - // SpawnChild creates a child span with the given operation name. The returned ChildSpan must - // be finished by calling its Finish method when the module is done with it. Returns nil if - // the child span could not be created. - SpawnChild(operationName string) ChildSpan -} - -// ChildSpan is a tracing span owned by the module. It must be finished by calling Finish when -// the module is done with it. -type ChildSpan interface { - // SetTag sets a key/value tag on the span. - SetTag(key, value string) - - // SetOperation sets the operation name on the span. - SetOperation(operation string) - - // Log records an event on the span with the current timestamp. - Log(event string) - - // SetSampled overrides the sampling decision for the span. - SetSampled(sampled bool) - - // SetBaggage sets a baggage value on the span. All subsequent child spans will have access to - // this baggage. - SetBaggage(key, value string) - - // SpawnChild creates a child span from this span with the given operation name. Returns nil - // if the child span could not be created. - SpawnChild(operationName string) ChildSpan - - // Finish finishes and releases this span. After calling this method, the span is no longer - // valid and must not be used. Calling Finish more than once is a no-op. - Finish() -} - -// DownstreamWatermarkCallbacks is the callback interface invoked when the downstream connection -// crosses the configured write-buffer high/low watermark. -type DownstreamWatermarkCallbacks interface { - OnAboveWriteBufferHighWatermark() - OnBelowWriteBufferLowWatermark() -} - -// HttpFilterHandle is the interface that provides access to the plugin's context and configuration. -// This should be implemented by the SDK or runtime. -type HttpFilterHandle interface { - // GetMetadataString retrieves the dynamic metadata string value of the stream. - // Returns metadata value if found, otherwise an empty UnsafeEnvoyBuffer. - GetMetadataString(source MetadataSourceType, metadataNamespace, key string) (UnsafeEnvoyBuffer, bool) - - // GetMetadataNumber retrieves the dynamic metadata number value of the stream. - // Returns metadata value if found, otherwise nil. - GetMetadataNumber(source MetadataSourceType, metadataNamespace, key string) (float64, bool) - - // GetMetadataBool retrieves the dynamic metadata bool value of the stream. - // Returns metadata value and true if found, otherwise false. - GetMetadataBool(source MetadataSourceType, metadataNamespace, key string) (bool, bool) - - // SetMetadata sets the dynamic metadata value of the stream. - SetMetadata(metadataNamespace, key string, value any) - - // GetMetadataKeys retrieves all keys in the given metadata namespace. - // Returns list of keys in the namespace, or nil if the namespace does not exist. - // NOTE: The memory of underlying data may not be managed by Go GC. So you should - // copy the data if you need to keep it and use it later. - GetMetadataKeys(source MetadataSourceType, metadataNamespace string) []UnsafeEnvoyBuffer - - // GetMetadataNamespaces retrieves all namespace names in the metadata. - // Returns list of namespace names, or nil if no namespaces exist. - // NOTE: The memory of underlying data may not be managed by Go GC. So you should - // copy the data if you need to keep it and use it later. - GetMetadataNamespaces(source MetadataSourceType) []UnsafeEnvoyBuffer - - // AddMetadataListNumber appends a number value to the dynamic metadata list stored under the - // given namespace and key. If the key does not exist, a new list is created. Returns false if - // the key exists but is not a list, or if the metadata is not accessible. - AddMetadataListNumber(metadataNamespace, key string, value float64) bool - - // AddMetadataListString appends a string value to the dynamic metadata list stored under the - // given namespace and key. If the key does not exist, a new list is created. Returns false if - // the key exists but is not a list, or if the metadata is not accessible. - AddMetadataListString(metadataNamespace, key string, value string) bool - - // AddMetadataListBool appends a bool value to the dynamic metadata list stored under the - // given namespace and key. If the key does not exist, a new list is created. Returns false if - // the key exists but is not a list, or if the metadata is not accessible. - AddMetadataListBool(metadataNamespace, key string, value bool) bool - - // GetMetadataListSize returns the number of elements in the metadata list stored under the - // given namespace and key. Returns (0, false) if the metadata is not accessible, the namespace - // or key does not exist, or the value is not a list. - GetMetadataListSize(source MetadataSourceType, metadataNamespace, key string) (int, bool) - - // GetMetadataListNumber returns the number element at the given index in the metadata list - // stored under the given namespace and key. Returns (0, false) if the metadata is not - // accessible, the namespace or key does not exist, the value is not a list, the index is out - // of range, or the element is not a number. - GetMetadataListNumber(source MetadataSourceType, metadataNamespace, key string, index int) (float64, bool) - - // GetMetadataListString returns the string element at the given index in the metadata list - // stored under the given namespace and key. Returns an empty buffer and false if the metadata is - // not accessible, the namespace or key does not exist, the value is not a list, the index is - // out of range, or the element is not a string. - // NOTE: The memory of underlying data may not be managed by Go GC. So you should - // copy the data if you need to keep it and use it later. - GetMetadataListString(source MetadataSourceType, metadataNamespace, key string, index int) (UnsafeEnvoyBuffer, bool) - - // GetMetadataListBool returns the bool element at the given index in the metadata list stored - // under the given namespace and key. Returns (false, false) if the metadata is not accessible, - // the namespace or key does not exist, the value is not a list, the index is out of range, or - // the element is not a bool. - GetMetadataListBool(source MetadataSourceType, metadataNamespace, key string, index int) (bool, bool) - - // GetFilterState retrieves the serialized filter state value of the stream. - // Returns filter state value if found, otherwise an empty UnsafeEnvoyBuffer. - // NOTE: The memory of underlying data may not be managed by Go GC. So you should - // copy the data if you need to keep it and use it later. - GetFilterState(key string) (UnsafeEnvoyBuffer, bool) - - // SetFilterState sets the serialized filter state value of the stream. - SetFilterState(key string, value []byte) - - // SetFilterStateTyped sets the typed filter state value stored under the given key. The key - // MUST match a registered ObjectFactory; the bytes are passed to createFromBytes on that - // factory. This is the form required for interop with built-in Envoy filters that read filter - // state as typed objects (e.g., tcp_proxy reading PerConnectionCluster). - // Returns true on success, or false if no factory is registered for the key, the factory - // failed to create the object, or the key is read-only. - SetFilterStateTyped(key string, value []byte) bool - - // GetAttributeString retrieves the string attribute value of the stream. - // Returns attribute value if found, otherwise an empty UnsafeEnvoyBuffer. - // NOTE: The memory of underlying data may not be managed by Go GC. So you should - // copy the data if you need to keep it and use it later. - GetAttributeString(attributeID AttributeID) (UnsafeEnvoyBuffer, bool) - - // GetAttributeNumber retrieves the integer attribute value of the stream. - // Returns attribute value if found, otherwise (0, false). - GetAttributeNumber(attributeID AttributeID) (uint64, bool) - - // GetAttributeBool retrieves the bool attribute value of the stream. - // Returns attribute value and true if found, otherwise false. - GetAttributeBool(attributeID AttributeID) (bool, bool) - - // GetFilterStateTyped retrieves the serialized bytes of a typed filter state object stored - // under the given key. Unlike GetFilterState, this calls serializeAsString on the registered - // typed object, so it works for any filter state object type (not just StringAccessor). - // Returns serialized value if found, otherwise an empty UnsafeEnvoyBuffer and false. - // NOTE: The memory of the underlying data may not be managed by Go GC. Copy the data if you - // need to keep it past the current callback. - GetFilterStateTyped(key string) (UnsafeEnvoyBuffer, bool) - - // GetData retrieves internal data stored for cross-phase communication. - // This data is not included in DynamicMetadata responses. - // Returns data value if found, otherwise nil. - GetData(key string) any - - // SetData sets internal data for cross-phase communication. - // This data is not included in DynamicMetadata responses. - SetData(key string, value any) - - // SendLocalResponse sends a local reply to the client and terminates the stream. - SendLocalResponse(status uint32, headers [][2]string, body []byte, detail string) - - // SendResponseHeaders sends response headers to the client. This is used for - // streaming local replies. - SendResponseHeaders(headers [][2]string, endOfStream bool) - - // SendResponseData sends response body data to the client. This is used for - // streaming local replies. - SendResponseData(body []byte, endOfStream bool) - - // SendResponseTrailers sends response trailers to the client. This is used for - // streaming local replies. - SendResponseTrailers(trailers [][2]string) - - // AddCustomFlag adds a custom flag to the stream. This flag should be very short - // string to indicate some custom state or information of the stream. - AddCustomFlag(flag string) - - // ContinueRequest continues the request stream processing. - // NOTE: This function should only be called when the plugin chains are hung up because - // of asynchronous operations. - ContinueRequest() - - // ContinueResponse continues the response stream processing. - // NOTE: This function should only be called when the plugin chains are hung up because - // of asynchronous operations. - ContinueResponse() - - // ClearRouteCache clears the cached route for the stream. - ClearRouteCache() - - // RefreshRouteCluster clears only the cluster selection for the current route without - // clearing the entire route cache. - // This is a subset of ClearRouteCache. Use this when a filter modifies headers that affect - // cluster selection but not the route itself. - RefreshRouteCluster() - - // GetWorkerIndex returns the worker thread index assigned to the current HTTP filter. - // This can be used by the module to manage worker-specific resources. - GetWorkerIndex() uint32 - - // SetSocketOptionInt sets an integer-valued socket option on the upstream or downstream - // connection associated with the stream. Returns true on success. - SetSocketOptionInt(level, name int64, state SocketOptionState, direction SocketDirection, value int64) bool - - // SetSocketOptionBytes sets a bytes-valued socket option on the upstream or downstream - // connection associated with the stream. Returns true on success. - SetSocketOptionBytes(level, name int64, state SocketOptionState, direction SocketDirection, value []byte) bool - - // GetSocketOptionInt retrieves the integer value of a socket option. - // Returns value and true if found, otherwise 0 and false. - GetSocketOptionInt(level, name int64, state SocketOptionState, direction SocketDirection) (int64, bool) - - // GetSocketOptionBytes retrieves the bytes value of a socket option. The buffer is owned by - // Envoy and remains valid until the filter is destroyed. - // Returns value and true if found, otherwise an empty UnsafeEnvoyBuffer and false. - // NOTE: The memory of the underlying data may not be managed by Go GC. Copy the data if you - // need to keep it past the current callback. - GetSocketOptionBytes(level, name int64, state SocketOptionState, direction SocketDirection) (UnsafeEnvoyBuffer, bool) - - // GetBufferLimit returns the current per-stream body buffer limit in bytes. A limit of 0 - // indicates no limit is applied. - GetBufferLimit() uint64 - - // SetBufferLimit sets the per-stream body buffer limit. It is recommended (but not required) - // that filters only INCREASE the limit, to avoid conflicting with the buffer requirements of - // other filters in the chain. - SetBufferLimit(limit uint64) - - // GetActiveSpan returns the active tracing span for the stream, or nil if tracing is disabled - // or no span is available. The returned Span is owned by Envoy; do not Finish it. Use - // Span.SpawnChild to create module-owned child spans. - GetActiveSpan() Span - - // GetClusterName returns the name of the cluster the current request is routed to. - // Returns cluster name and true if found, otherwise an empty UnsafeEnvoyBuffer and false. - // NOTE: The memory of the underlying data may not be managed by Go GC. Copy the data if you - // need to keep it past the current callback. - GetClusterName() (UnsafeEnvoyBuffer, bool) - - // GetClusterHostCounts returns the host counts for the routed cluster at the given priority. - // Returns host counts and true if successful, otherwise a zero-valued struct and false. - GetClusterHostCounts(priority uint32) (ClusterHostCounts, bool) - - // SetUpstreamOverrideHost sets a host that the upstream load balancer should select first - // if it exists in the routed cluster. Useful for sticky sessions or host affinity. When - // strict is false, normal load balancing is used as a fallback. Returns false if the host - // address was invalid. - SetUpstreamOverrideHost(host string, strict bool) bool - - // ResetStream resets the HTTP stream with the given reason and optional details. After this - // call, no further filter callbacks will be invoked except OnDestroy. - ResetStream(reason HttpFilterStreamResetReason, details string) - - // SendGoAwayAndClose sends a GOAWAY frame to the downstream and closes the connection. If - // graceful is true, a graceful drain is initiated before closing. - SendGoAwayAndClose(graceful bool) - - // RecreateStream recreates the HTTP stream, optionally with new headers (or with the original - // headers if headers is nil). Useful for internal redirects or request retries. After a - // successful call, the current filter chain is destroyed and the filter SHOULD return Stop - // from the current callback. Returns false if recreation could not be initiated (e.g., the - // request body has not been fully received yet). - RecreateStream(headers [][2]string) bool - - // RequestHeaders retrieves the request headers. - RequestHeaders() HeaderMap - - // BufferedRequestBody retrieves the buffered request body in the chain. - // NOTE: Because of streaming processing, the request body is not always fully buffered. - // This function only retrieves the currently buffered body in the chain. The latest newly - // received body chunk is passed as the parameter to OnRequestBody. Only when endOfStream is - // true or OnRequestTrailers is called is the full request body received. - BufferedRequestBody() BodyBuffer - - // ReceivedRequestBody retrieves the latest received request body chunk in the OnRequestBody - // callback. - // NOTE: This is only valid in the OnRequestBody callback. For other callbacks or outside of - // callbacks, use BufferedRequestBody to get the currently buffered body in the chain. - ReceivedRequestBody() BodyBuffer - - // RequestTrailers retrieves the request trailers. - RequestTrailers() HeaderMap - - // ResponseHeaders retrieves the response headers. - ResponseHeaders() HeaderMap - - // BufferedResponseBody retrieves the buffered response body in the chain. See - // BufferedRequestBody for the buffering caveats. - BufferedResponseBody() BodyBuffer - - // ReceivedResponseBody retrieves the latest received response body chunk in the OnResponseBody - // callback. - // NOTE: This is only valid in the OnResponseBody callback. For other callbacks or outside of - // callbacks, use BufferedResponseBody to get the currently buffered body in the chain. - ReceivedResponseBody() BodyBuffer - - // ReceivedBufferedRequestBody returns true if the latest received request body is the - // previously buffered request body. This is true when a previous filter in the chain stopped - // and buffered the request body, then resumed, and this filter is now receiving that buffered - // body. - // NOTE: This is only meaningful inside the OnRequestBody callback. - ReceivedBufferedRequestBody() bool - - // ReceivedBufferedResponseBody returns true if the latest received response body is the - // previously buffered response body. This is true when a previous filter in the chain stopped - // and buffered the response body, then resumed, and this filter is now receiving that buffered - // body. - // NOTE: This is only meaningful inside the OnResponseBody callback. - ReceivedBufferedResponseBody() bool - - // ResponseTrailers retrieves the response trailers. - ResponseTrailers() HeaderMap - - // GetMostSpecificConfig retrieves the most specific route configuration for the stream. - GetMostSpecificConfig() any - - // GetScheduler retrieves the scheduler related to this stream plugin for asynchronous - // operations. - // - // NOTE: This MUST only be called during OnRequest* or OnResponse* callbacks. But then the - // returned Scheduler can be used later even outside of the callbacks and even at other - // threads. - GetScheduler() Scheduler - - // Log will log the given message via the host environment's logging mechanism. - Log(level LogLevel, format string, args ...any) - - // HttpCallout performs an HTTP call to an external service. The call is asynchronous; the - // response, or an error, is delivered to the provided callback. - // - // Returns the initialization result and the callout ID. A non-success result indicates the - // callout failed to start. - // - // NOTE: This method should only be called during OnRequest* or OnResponse* callbacks or - // from a scheduled function, so that it runs on the thread where the stream is being - // processed. - HttpCallout(cluster string, headers [][2]string, body []byte, timeoutMs uint64, - cb HttpCalloutCallback) (HttpCalloutInitResult, uint64) - - // StartHttpStream starts a new HTTP stream to an external service. The stream is asynchronous; - // responses are delivered to the provided callback. - // - // Returns the initialization result and the stream ID. A non-success result indicates the - // stream failed to start. - // - // NOTE: This method should only be called during OnRequest* or OnResponse* callbacks or - // from a scheduled function, so that it runs on the thread where the stream is being - // processed. - StartHttpStream(cluster string, headers [][2]string, body []byte, endOfStream bool, timeoutMs uint64, - cb HttpStreamCallback) (HttpCalloutInitResult, uint64) - - // SendHttpStreamData sends data on an existing HTTP stream. Returns true if the data was - // sent successfully. - // - // NOTE: This method should only be called during OnRequest* or OnResponse* callbacks or - // from a scheduled function, so that it runs on the thread where the stream is being - // processed. - SendHttpStreamData(streamID uint64, body []byte, endOfStream bool) bool - - // SendHttpStreamTrailers sends trailers on an existing HTTP stream. Returns true if the - // trailers were sent successfully. - // - // NOTE: This method should only be called during OnRequest* or OnResponse* callbacks or - // from a scheduled function, so that it runs on the thread where the stream is being - // processed. - SendHttpStreamTrailers(streamID uint64, trailers [][2]string) bool - - // ResetHttpStream resets an existing HTTP stream. - // - // NOTE: This method should only be called during OnRequest* or OnResponse* callbacks or - // from a scheduled function, so that it runs on the thread where the stream is being - // processed. - ResetHttpStream(streamID uint64) - - // SetDownstreamWatermarkCallbacks sets the downstream watermark callbacks for the stream. - SetDownstreamWatermarkCallbacks(callbacks DownstreamWatermarkCallbacks) - - // ClearDownstreamWatermarkCallbacks unsets the downstream watermark callbacks for the stream. - ClearDownstreamWatermarkCallbacks() - - // RecordHistogramValue records the given value to the histogram metric. The order and - // size of tagsValues must match the tag keys defined when the metric was created. - RecordHistogramValue(id MetricID, value uint64, tagsValues ...string) MetricsResult - - // SetGaugeValue sets the given value on the gauge metric. The order and size of - // tagsValues must match the tag keys defined when the metric was created. - SetGaugeValue(id MetricID, value uint64, tagsValues ...string) MetricsResult - - // IncrementGaugeValue adds the given value to the gauge metric. The order and size of - // tagsValues must match the tag keys defined when the metric was created. - IncrementGaugeValue(id MetricID, value uint64, tagsValues ...string) MetricsResult - - // DecrementGaugeValue subtracts the given value from the gauge metric. The order and - // size of tagsValues must match the tag keys defined when the metric was created. - DecrementGaugeValue(id MetricID, value uint64, tagsValues ...string) MetricsResult - - // IncrementCounterValue adds the given value to the counter metric. The order and - // size of tagsValues must match the tag keys defined when the metric was created. - IncrementCounterValue(id MetricID, value uint64, tagsValues ...string) MetricsResult -} - -// HttpFilterConfigHandle is the per-filter-config handle exposed to HttpFilterConfig -// implementations. It supports config-scoped logging, metric definition, and async I/O via -// HttpCallout / StartHttpStream from the main thread. -type HttpFilterConfigHandle interface { - // Log will log the given message via the host environment's logging mechanism. - Log(level LogLevel, format string, args ...any) - - // DefineHistogram creates a histogram metric with the given name, and tag keys. - // Returns histogram metric id. This metric can never be used after the plugin - // config is unloaded. - DefineHistogram(name string, tagKeys ...string) (MetricID, MetricsResult) - - // DefineGauge creates a gauge metric with the given name, description, and tag keys. - // Returns gauge metric id. This metric can never be used after the plugin - // config is unloaded. - DefineGauge(name string, tagKeys ...string) (MetricID, MetricsResult) - - // DefineCounter creates a counter metric with the given name, description, and tag keys. - // Returns counter metric id. This metric can never be used after the plugin - // config is unloaded. - DefineCounter(name string, tagKeys ...string) (MetricID, MetricsResult) - - // HttpCallout performs an HTTP call to an external service from the config context. - // The call is asynchronous, and the response will be delivered via the provided callback. - // This is similar to HttpFilterHandle.HttpCallout but runs on the main thread rather than - // the worker thread. - // Returns result of the HTTP callout initialization and the callout ID. - HttpCallout(cluster string, headers [][2]string, body []byte, timeoutMs uint64, - cb HttpCalloutCallback) (HttpCalloutInitResult, uint64) - - // StartHttpStream starts a new HTTP stream to an external service from the config context. - // The stream is asynchronous, and the response will be delivered via the provided callback. - // This is similar to HttpFilterHandle.StartHttpStream but runs on the main thread. - // Returns result of the HTTP stream initialization and the stream ID. - StartHttpStream(cluster string, headers [][2]string, body []byte, endOfStream bool, - timeoutMs uint64, cb HttpStreamCallback) (HttpCalloutInitResult, uint64) - - // SendHttpStreamData sends data on an existing HTTP stream started via StartHttpStream. - // Returns true if the data was sent successfully. - SendHttpStreamData(streamID uint64, body []byte, endOfStream bool) bool - - // SendHttpStreamTrailers sends trailers on an existing HTTP stream started via StartHttpStream. - // Returns true if the trailers were sent successfully. - SendHttpStreamTrailers(streamID uint64, trailers [][2]string) bool - - // ResetHttpStream resets an existing HTTP stream started via StartHttpStream. - ResetHttpStream(streamID uint64) - - // GetScheduler retrieves a scheduler for deferred task execution in the config context. - // This should be called only during the plugin configuration phase, and the returned - // Scheduler can be used later even outside of the callbacks and at other threads. - GetScheduler() Scheduler -} diff --git a/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_http_api.go b/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_api.go similarity index 98% rename from source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_http_api.go rename to source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_api.go index 2a53851cbeadd..34dae5915c643 100644 --- a/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_http_api.go +++ b/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_api.go @@ -1,9 +1,9 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: http_api.go +// Source: api.go // // Generated by this command: // -// mockgen -source=http_api.go -destination=mocks/mock_http_api.go -package=mocks +// mockgen -source=api.go -destination=mocks/mock_api.go -package=mocks // // Package mocks is a generated GoMock package. diff --git a/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_http.go b/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_base.go similarity index 88% rename from source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_http.go rename to source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_base.go index 7e2a6a8b981cd..0793e6d3fcdfc 100644 --- a/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_http.go +++ b/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_base.go @@ -1,9 +1,9 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: http.go +// Source: base.go // // Generated by this command: // -// mockgen -source=http.go -destination=mocks/mock_http.go -package=mocks +// mockgen -source=base.go -destination=mocks/mock_base.go -package=mocks // // Package mocks is a generated GoMock package. @@ -194,6 +194,210 @@ func (mr *MockHeaderMapMockRecorder) Set(key, value any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Set", reflect.TypeOf((*MockHeaderMap)(nil).Set), key, value) } +// MockHttpCalloutCallback is a mock of HttpCalloutCallback interface. +type MockHttpCalloutCallback struct { + ctrl *gomock.Controller + recorder *MockHttpCalloutCallbackMockRecorder + isgomock struct{} +} + +// MockHttpCalloutCallbackMockRecorder is the mock recorder for MockHttpCalloutCallback. +type MockHttpCalloutCallbackMockRecorder struct { + mock *MockHttpCalloutCallback +} + +// NewMockHttpCalloutCallback creates a new mock instance. +func NewMockHttpCalloutCallback(ctrl *gomock.Controller) *MockHttpCalloutCallback { + mock := &MockHttpCalloutCallback{ctrl: ctrl} + mock.recorder = &MockHttpCalloutCallbackMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockHttpCalloutCallback) EXPECT() *MockHttpCalloutCallbackMockRecorder { + return m.recorder +} + +// OnHttpCalloutDone mocks base method. +func (m *MockHttpCalloutCallback) OnHttpCalloutDone(calloutID uint64, result shared.HttpCalloutResult, headers [][2]shared.UnsafeEnvoyBuffer, body []shared.UnsafeEnvoyBuffer) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OnHttpCalloutDone", calloutID, result, headers, body) +} + +// OnHttpCalloutDone indicates an expected call of OnHttpCalloutDone. +func (mr *MockHttpCalloutCallbackMockRecorder) OnHttpCalloutDone(calloutID, result, headers, body any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnHttpCalloutDone", reflect.TypeOf((*MockHttpCalloutCallback)(nil).OnHttpCalloutDone), calloutID, result, headers, body) +} + +// MockHttpStreamCallback is a mock of HttpStreamCallback interface. +type MockHttpStreamCallback struct { + ctrl *gomock.Controller + recorder *MockHttpStreamCallbackMockRecorder + isgomock struct{} +} + +// MockHttpStreamCallbackMockRecorder is the mock recorder for MockHttpStreamCallback. +type MockHttpStreamCallbackMockRecorder struct { + mock *MockHttpStreamCallback +} + +// NewMockHttpStreamCallback creates a new mock instance. +func NewMockHttpStreamCallback(ctrl *gomock.Controller) *MockHttpStreamCallback { + mock := &MockHttpStreamCallback{ctrl: ctrl} + mock.recorder = &MockHttpStreamCallbackMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockHttpStreamCallback) EXPECT() *MockHttpStreamCallbackMockRecorder { + return m.recorder +} + +// OnHttpStreamComplete mocks base method. +func (m *MockHttpStreamCallback) OnHttpStreamComplete(streamID uint64) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OnHttpStreamComplete", streamID) +} + +// OnHttpStreamComplete indicates an expected call of OnHttpStreamComplete. +func (mr *MockHttpStreamCallbackMockRecorder) OnHttpStreamComplete(streamID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnHttpStreamComplete", reflect.TypeOf((*MockHttpStreamCallback)(nil).OnHttpStreamComplete), streamID) +} + +// OnHttpStreamData mocks base method. +func (m *MockHttpStreamCallback) OnHttpStreamData(streamID uint64, body []shared.UnsafeEnvoyBuffer, endStream bool) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OnHttpStreamData", streamID, body, endStream) +} + +// OnHttpStreamData indicates an expected call of OnHttpStreamData. +func (mr *MockHttpStreamCallbackMockRecorder) OnHttpStreamData(streamID, body, endStream any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnHttpStreamData", reflect.TypeOf((*MockHttpStreamCallback)(nil).OnHttpStreamData), streamID, body, endStream) +} + +// OnHttpStreamHeaders mocks base method. +func (m *MockHttpStreamCallback) OnHttpStreamHeaders(streamID uint64, headers [][2]shared.UnsafeEnvoyBuffer, endStream bool) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OnHttpStreamHeaders", streamID, headers, endStream) +} + +// OnHttpStreamHeaders indicates an expected call of OnHttpStreamHeaders. +func (mr *MockHttpStreamCallbackMockRecorder) OnHttpStreamHeaders(streamID, headers, endStream any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnHttpStreamHeaders", reflect.TypeOf((*MockHttpStreamCallback)(nil).OnHttpStreamHeaders), streamID, headers, endStream) +} + +// OnHttpStreamReset mocks base method. +func (m *MockHttpStreamCallback) OnHttpStreamReset(streamID uint64, reason shared.HttpStreamResetReason) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OnHttpStreamReset", streamID, reason) +} + +// OnHttpStreamReset indicates an expected call of OnHttpStreamReset. +func (mr *MockHttpStreamCallbackMockRecorder) OnHttpStreamReset(streamID, reason any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnHttpStreamReset", reflect.TypeOf((*MockHttpStreamCallback)(nil).OnHttpStreamReset), streamID, reason) +} + +// OnHttpStreamTrailers mocks base method. +func (m *MockHttpStreamCallback) OnHttpStreamTrailers(streamID uint64, trailers [][2]shared.UnsafeEnvoyBuffer) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OnHttpStreamTrailers", streamID, trailers) +} + +// OnHttpStreamTrailers indicates an expected call of OnHttpStreamTrailers. +func (mr *MockHttpStreamCallbackMockRecorder) OnHttpStreamTrailers(streamID, trailers any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnHttpStreamTrailers", reflect.TypeOf((*MockHttpStreamCallback)(nil).OnHttpStreamTrailers), streamID, trailers) +} + +// MockScheduler is a mock of Scheduler interface. +type MockScheduler struct { + ctrl *gomock.Controller + recorder *MockSchedulerMockRecorder + isgomock struct{} +} + +// MockSchedulerMockRecorder is the mock recorder for MockScheduler. +type MockSchedulerMockRecorder struct { + mock *MockScheduler +} + +// NewMockScheduler creates a new mock instance. +func NewMockScheduler(ctrl *gomock.Controller) *MockScheduler { + mock := &MockScheduler{ctrl: ctrl} + mock.recorder = &MockSchedulerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockScheduler) EXPECT() *MockSchedulerMockRecorder { + return m.recorder +} + +// Schedule mocks base method. +func (m *MockScheduler) Schedule(arg0 func()) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Schedule", arg0) +} + +// Schedule indicates an expected call of Schedule. +func (mr *MockSchedulerMockRecorder) Schedule(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Schedule", reflect.TypeOf((*MockScheduler)(nil).Schedule), arg0) +} + +// MockDownstreamWatermarkCallbacks is a mock of DownstreamWatermarkCallbacks interface. +type MockDownstreamWatermarkCallbacks struct { + ctrl *gomock.Controller + recorder *MockDownstreamWatermarkCallbacksMockRecorder + isgomock struct{} +} + +// MockDownstreamWatermarkCallbacksMockRecorder is the mock recorder for MockDownstreamWatermarkCallbacks. +type MockDownstreamWatermarkCallbacksMockRecorder struct { + mock *MockDownstreamWatermarkCallbacks +} + +// NewMockDownstreamWatermarkCallbacks creates a new mock instance. +func NewMockDownstreamWatermarkCallbacks(ctrl *gomock.Controller) *MockDownstreamWatermarkCallbacks { + mock := &MockDownstreamWatermarkCallbacks{ctrl: ctrl} + mock.recorder = &MockDownstreamWatermarkCallbacksMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockDownstreamWatermarkCallbacks) EXPECT() *MockDownstreamWatermarkCallbacksMockRecorder { + return m.recorder +} + +// OnAboveWriteBufferHighWatermark mocks base method. +func (m *MockDownstreamWatermarkCallbacks) OnAboveWriteBufferHighWatermark() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OnAboveWriteBufferHighWatermark") +} + +// OnAboveWriteBufferHighWatermark indicates an expected call of OnAboveWriteBufferHighWatermark. +func (mr *MockDownstreamWatermarkCallbacksMockRecorder) OnAboveWriteBufferHighWatermark() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnAboveWriteBufferHighWatermark", reflect.TypeOf((*MockDownstreamWatermarkCallbacks)(nil).OnAboveWriteBufferHighWatermark)) +} + +// OnBelowWriteBufferLowWatermark mocks base method. +func (m *MockDownstreamWatermarkCallbacks) OnBelowWriteBufferLowWatermark() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OnBelowWriteBufferLowWatermark") +} + +// OnBelowWriteBufferLowWatermark indicates an expected call of OnBelowWriteBufferLowWatermark. +func (mr *MockDownstreamWatermarkCallbacksMockRecorder) OnBelowWriteBufferLowWatermark() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnBelowWriteBufferLowWatermark", reflect.TypeOf((*MockDownstreamWatermarkCallbacks)(nil).OnBelowWriteBufferLowWatermark)) +} + // MockSpan is a mock of Span interface. type MockSpan struct { ctrl *gomock.Controller @@ -324,17 +528,17 @@ func (mr *MockSpanMockRecorder) SetTag(key, value any) *gomock.Call { } // SpawnChild mocks base method. -func (m *MockSpan) SpawnChild(operationName string) shared.ChildSpan { +func (m *MockSpan) SpawnChild(operation string) shared.ChildSpan { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SpawnChild", operationName) + ret := m.ctrl.Call(m, "SpawnChild", operation) ret0, _ := ret[0].(shared.ChildSpan) return ret0 } // SpawnChild indicates an expected call of SpawnChild. -func (mr *MockSpanMockRecorder) SpawnChild(operationName any) *gomock.Call { +func (mr *MockSpanMockRecorder) SpawnChild(operation any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpawnChild", reflect.TypeOf((*MockSpan)(nil).SpawnChild), operationName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpawnChild", reflect.TypeOf((*MockSpan)(nil).SpawnChild), operation) } // MockChildSpan is a mock of ChildSpan interface. @@ -373,6 +577,51 @@ func (mr *MockChildSpanMockRecorder) Finish() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Finish", reflect.TypeOf((*MockChildSpan)(nil).Finish)) } +// GetBaggage mocks base method. +func (m *MockChildSpan) GetBaggage(key string) (shared.UnsafeEnvoyBuffer, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetBaggage", key) + ret0, _ := ret[0].(shared.UnsafeEnvoyBuffer) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// GetBaggage indicates an expected call of GetBaggage. +func (mr *MockChildSpanMockRecorder) GetBaggage(key any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBaggage", reflect.TypeOf((*MockChildSpan)(nil).GetBaggage), key) +} + +// GetSpanID mocks base method. +func (m *MockChildSpan) GetSpanID() (shared.UnsafeEnvoyBuffer, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSpanID") + ret0, _ := ret[0].(shared.UnsafeEnvoyBuffer) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// GetSpanID indicates an expected call of GetSpanID. +func (mr *MockChildSpanMockRecorder) GetSpanID() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSpanID", reflect.TypeOf((*MockChildSpan)(nil).GetSpanID)) +} + +// GetTraceID mocks base method. +func (m *MockChildSpan) GetTraceID() (shared.UnsafeEnvoyBuffer, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTraceID") + ret0, _ := ret[0].(shared.UnsafeEnvoyBuffer) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// GetTraceID indicates an expected call of GetTraceID. +func (mr *MockChildSpanMockRecorder) GetTraceID() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTraceID", reflect.TypeOf((*MockChildSpan)(nil).GetTraceID)) +} + // Log mocks base method. func (m *MockChildSpan) Log(event string) { m.ctrl.T.Helper() @@ -434,65 +683,17 @@ func (mr *MockChildSpanMockRecorder) SetTag(key, value any) *gomock.Call { } // SpawnChild mocks base method. -func (m *MockChildSpan) SpawnChild(operationName string) shared.ChildSpan { +func (m *MockChildSpan) SpawnChild(operation string) shared.ChildSpan { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SpawnChild", operationName) + ret := m.ctrl.Call(m, "SpawnChild", operation) ret0, _ := ret[0].(shared.ChildSpan) return ret0 } // SpawnChild indicates an expected call of SpawnChild. -func (mr *MockChildSpanMockRecorder) SpawnChild(operationName any) *gomock.Call { +func (mr *MockChildSpanMockRecorder) SpawnChild(operation any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpawnChild", reflect.TypeOf((*MockChildSpan)(nil).SpawnChild), operationName) -} - -// MockDownstreamWatermarkCallbacks is a mock of DownstreamWatermarkCallbacks interface. -type MockDownstreamWatermarkCallbacks struct { - ctrl *gomock.Controller - recorder *MockDownstreamWatermarkCallbacksMockRecorder - isgomock struct{} -} - -// MockDownstreamWatermarkCallbacksMockRecorder is the mock recorder for MockDownstreamWatermarkCallbacks. -type MockDownstreamWatermarkCallbacksMockRecorder struct { - mock *MockDownstreamWatermarkCallbacks -} - -// NewMockDownstreamWatermarkCallbacks creates a new mock instance. -func NewMockDownstreamWatermarkCallbacks(ctrl *gomock.Controller) *MockDownstreamWatermarkCallbacks { - mock := &MockDownstreamWatermarkCallbacks{ctrl: ctrl} - mock.recorder = &MockDownstreamWatermarkCallbacksMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockDownstreamWatermarkCallbacks) EXPECT() *MockDownstreamWatermarkCallbacksMockRecorder { - return m.recorder -} - -// OnAboveWriteBufferHighWatermark mocks base method. -func (m *MockDownstreamWatermarkCallbacks) OnAboveWriteBufferHighWatermark() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "OnAboveWriteBufferHighWatermark") -} - -// OnAboveWriteBufferHighWatermark indicates an expected call of OnAboveWriteBufferHighWatermark. -func (mr *MockDownstreamWatermarkCallbacksMockRecorder) OnAboveWriteBufferHighWatermark() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnAboveWriteBufferHighWatermark", reflect.TypeOf((*MockDownstreamWatermarkCallbacks)(nil).OnAboveWriteBufferHighWatermark)) -} - -// OnBelowWriteBufferLowWatermark mocks base method. -func (m *MockDownstreamWatermarkCallbacks) OnBelowWriteBufferLowWatermark() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "OnBelowWriteBufferLowWatermark") -} - -// OnBelowWriteBufferLowWatermark indicates an expected call of OnBelowWriteBufferLowWatermark. -func (mr *MockDownstreamWatermarkCallbacksMockRecorder) OnBelowWriteBufferLowWatermark() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnBelowWriteBufferLowWatermark", reflect.TypeOf((*MockDownstreamWatermarkCallbacks)(nil).OnBelowWriteBufferLowWatermark)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpawnChild", reflect.TypeOf((*MockChildSpan)(nil).SpawnChild), operation) } // MockHttpFilterHandle is a mock of HttpFilterHandle interface. @@ -698,10 +899,10 @@ func (mr *MockHttpFilterHandleMockRecorder) GetAttributeBool(attributeID any) *g } // GetAttributeNumber mocks base method. -func (m *MockHttpFilterHandle) GetAttributeNumber(attributeID shared.AttributeID) (uint64, bool) { +func (m *MockHttpFilterHandle) GetAttributeNumber(attributeID shared.AttributeID) (float64, bool) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetAttributeNumber", attributeID) - ret0, _ := ret[0].(uint64) + ret0, _ := ret[0].(float64) ret1, _ := ret[1].(bool) return ret0, ret1 } diff --git a/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_network_api.go b/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_network_api.go deleted file mode 100644 index a8cc08bd0de40..0000000000000 --- a/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_network_api.go +++ /dev/null @@ -1,220 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: network_api.go -// -// Generated by this command: -// -// mockgen -source=network_api.go -destination=mocks/mock_network_api.go -package=mocks -// - -// Package mocks is a generated GoMock package. -package mocks - -import ( - reflect "reflect" - - shared "github.com/envoyproxy/envoy/source/extensions/dynamic_modules/sdk/go/shared" - gomock "go.uber.org/mock/gomock" -) - -// MockNetworkFilter is a mock of NetworkFilter interface. -type MockNetworkFilter struct { - ctrl *gomock.Controller - recorder *MockNetworkFilterMockRecorder - isgomock struct{} -} - -// MockNetworkFilterMockRecorder is the mock recorder for MockNetworkFilter. -type MockNetworkFilterMockRecorder struct { - mock *MockNetworkFilter -} - -// NewMockNetworkFilter creates a new mock instance. -func NewMockNetworkFilter(ctrl *gomock.Controller) *MockNetworkFilter { - mock := &MockNetworkFilter{ctrl: ctrl} - mock.recorder = &MockNetworkFilterMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockNetworkFilter) EXPECT() *MockNetworkFilterMockRecorder { - return m.recorder -} - -// OnAboveWriteBufferHighWatermark mocks base method. -func (m *MockNetworkFilter) OnAboveWriteBufferHighWatermark() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "OnAboveWriteBufferHighWatermark") -} - -// OnAboveWriteBufferHighWatermark indicates an expected call of OnAboveWriteBufferHighWatermark. -func (mr *MockNetworkFilterMockRecorder) OnAboveWriteBufferHighWatermark() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnAboveWriteBufferHighWatermark", reflect.TypeOf((*MockNetworkFilter)(nil).OnAboveWriteBufferHighWatermark)) -} - -// OnBelowWriteBufferLowWatermark mocks base method. -func (m *MockNetworkFilter) OnBelowWriteBufferLowWatermark() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "OnBelowWriteBufferLowWatermark") -} - -// OnBelowWriteBufferLowWatermark indicates an expected call of OnBelowWriteBufferLowWatermark. -func (mr *MockNetworkFilterMockRecorder) OnBelowWriteBufferLowWatermark() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnBelowWriteBufferLowWatermark", reflect.TypeOf((*MockNetworkFilter)(nil).OnBelowWriteBufferLowWatermark)) -} - -// OnDestroy mocks base method. -func (m *MockNetworkFilter) OnDestroy() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "OnDestroy") -} - -// OnDestroy indicates an expected call of OnDestroy. -func (mr *MockNetworkFilterMockRecorder) OnDestroy() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnDestroy", reflect.TypeOf((*MockNetworkFilter)(nil).OnDestroy)) -} - -// OnEvent mocks base method. -func (m *MockNetworkFilter) OnEvent(event shared.NetworkConnectionEvent) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "OnEvent", event) -} - -// OnEvent indicates an expected call of OnEvent. -func (mr *MockNetworkFilterMockRecorder) OnEvent(event any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnEvent", reflect.TypeOf((*MockNetworkFilter)(nil).OnEvent), event) -} - -// OnNewConnection mocks base method. -func (m *MockNetworkFilter) OnNewConnection() shared.NetworkFilterStatus { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnNewConnection") - ret0, _ := ret[0].(shared.NetworkFilterStatus) - return ret0 -} - -// OnNewConnection indicates an expected call of OnNewConnection. -func (mr *MockNetworkFilterMockRecorder) OnNewConnection() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnNewConnection", reflect.TypeOf((*MockNetworkFilter)(nil).OnNewConnection)) -} - -// OnRead mocks base method. -func (m *MockNetworkFilter) OnRead(data shared.NetworkBuffer, endOfStream bool) shared.NetworkFilterStatus { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnRead", data, endOfStream) - ret0, _ := ret[0].(shared.NetworkFilterStatus) - return ret0 -} - -// OnRead indicates an expected call of OnRead. -func (mr *MockNetworkFilterMockRecorder) OnRead(data, endOfStream any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnRead", reflect.TypeOf((*MockNetworkFilter)(nil).OnRead), data, endOfStream) -} - -// OnWrite mocks base method. -func (m *MockNetworkFilter) OnWrite(data shared.NetworkBuffer, endOfStream bool) shared.NetworkFilterStatus { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OnWrite", data, endOfStream) - ret0, _ := ret[0].(shared.NetworkFilterStatus) - return ret0 -} - -// OnWrite indicates an expected call of OnWrite. -func (mr *MockNetworkFilterMockRecorder) OnWrite(data, endOfStream any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnWrite", reflect.TypeOf((*MockNetworkFilter)(nil).OnWrite), data, endOfStream) -} - -// MockNetworkFilterFactory is a mock of NetworkFilterFactory interface. -type MockNetworkFilterFactory struct { - ctrl *gomock.Controller - recorder *MockNetworkFilterFactoryMockRecorder - isgomock struct{} -} - -// MockNetworkFilterFactoryMockRecorder is the mock recorder for MockNetworkFilterFactory. -type MockNetworkFilterFactoryMockRecorder struct { - mock *MockNetworkFilterFactory -} - -// NewMockNetworkFilterFactory creates a new mock instance. -func NewMockNetworkFilterFactory(ctrl *gomock.Controller) *MockNetworkFilterFactory { - mock := &MockNetworkFilterFactory{ctrl: ctrl} - mock.recorder = &MockNetworkFilterFactoryMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockNetworkFilterFactory) EXPECT() *MockNetworkFilterFactoryMockRecorder { - return m.recorder -} - -// Create mocks base method. -func (m *MockNetworkFilterFactory) Create(handle shared.NetworkFilterHandle) shared.NetworkFilter { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Create", handle) - ret0, _ := ret[0].(shared.NetworkFilter) - return ret0 -} - -// Create indicates an expected call of Create. -func (mr *MockNetworkFilterFactoryMockRecorder) Create(handle any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockNetworkFilterFactory)(nil).Create), handle) -} - -// OnDestroy mocks base method. -func (m *MockNetworkFilterFactory) OnDestroy() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "OnDestroy") -} - -// OnDestroy indicates an expected call of OnDestroy. -func (mr *MockNetworkFilterFactoryMockRecorder) OnDestroy() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnDestroy", reflect.TypeOf((*MockNetworkFilterFactory)(nil).OnDestroy)) -} - -// MockNetworkFilterConfigFactory is a mock of NetworkFilterConfigFactory interface. -type MockNetworkFilterConfigFactory struct { - ctrl *gomock.Controller - recorder *MockNetworkFilterConfigFactoryMockRecorder - isgomock struct{} -} - -// MockNetworkFilterConfigFactoryMockRecorder is the mock recorder for MockNetworkFilterConfigFactory. -type MockNetworkFilterConfigFactoryMockRecorder struct { - mock *MockNetworkFilterConfigFactory -} - -// NewMockNetworkFilterConfigFactory creates a new mock instance. -func NewMockNetworkFilterConfigFactory(ctrl *gomock.Controller) *MockNetworkFilterConfigFactory { - mock := &MockNetworkFilterConfigFactory{ctrl: ctrl} - mock.recorder = &MockNetworkFilterConfigFactoryMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockNetworkFilterConfigFactory) EXPECT() *MockNetworkFilterConfigFactoryMockRecorder { - return m.recorder -} - -// Create mocks base method. -func (m *MockNetworkFilterConfigFactory) Create(handle shared.NetworkFilterConfigHandle, unparsedConfig []byte) (shared.NetworkFilterFactory, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Create", handle, unparsedConfig) - ret0, _ := ret[0].(shared.NetworkFilterFactory) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Create indicates an expected call of Create. -func (mr *MockNetworkFilterConfigFactoryMockRecorder) Create(handle, unparsedConfig any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockNetworkFilterConfigFactory)(nil).Create), handle, unparsedConfig) -} diff --git a/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_network_base.go b/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_network_base.go deleted file mode 100644 index b42fd2634b665..0000000000000 --- a/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_network_base.go +++ /dev/null @@ -1,991 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: network_base.go -// -// Generated by this command: -// -// mockgen -source=network_base.go -destination=mocks/mock_network_base.go -package=mocks -// - -// Package mocks is a generated GoMock package. -package mocks - -import ( - reflect "reflect" - - shared "github.com/envoyproxy/envoy/source/extensions/dynamic_modules/sdk/go/shared" - gomock "go.uber.org/mock/gomock" -) - -// MockNetworkBuffer is a mock of NetworkBuffer interface. -type MockNetworkBuffer struct { - ctrl *gomock.Controller - recorder *MockNetworkBufferMockRecorder - isgomock struct{} -} - -// MockNetworkBufferMockRecorder is the mock recorder for MockNetworkBuffer. -type MockNetworkBufferMockRecorder struct { - mock *MockNetworkBuffer -} - -// NewMockNetworkBuffer creates a new mock instance. -func NewMockNetworkBuffer(ctrl *gomock.Controller) *MockNetworkBuffer { - mock := &MockNetworkBuffer{ctrl: ctrl} - mock.recorder = &MockNetworkBufferMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockNetworkBuffer) EXPECT() *MockNetworkBufferMockRecorder { - return m.recorder -} - -// Append mocks base method. -func (m *MockNetworkBuffer) Append(data []byte) bool { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Append", data) - ret0, _ := ret[0].(bool) - return ret0 -} - -// Append indicates an expected call of Append. -func (mr *MockNetworkBufferMockRecorder) Append(data any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Append", reflect.TypeOf((*MockNetworkBuffer)(nil).Append), data) -} - -// Drain mocks base method. -func (m *MockNetworkBuffer) Drain(numBytes uint64) bool { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Drain", numBytes) - ret0, _ := ret[0].(bool) - return ret0 -} - -// Drain indicates an expected call of Drain. -func (mr *MockNetworkBufferMockRecorder) Drain(numBytes any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Drain", reflect.TypeOf((*MockNetworkBuffer)(nil).Drain), numBytes) -} - -// GetChunks mocks base method. -func (m *MockNetworkBuffer) GetChunks() []shared.UnsafeEnvoyBuffer { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetChunks") - ret0, _ := ret[0].([]shared.UnsafeEnvoyBuffer) - return ret0 -} - -// GetChunks indicates an expected call of GetChunks. -func (mr *MockNetworkBufferMockRecorder) GetChunks() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetChunks", reflect.TypeOf((*MockNetworkBuffer)(nil).GetChunks)) -} - -// GetSize mocks base method. -func (m *MockNetworkBuffer) GetSize() uint64 { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetSize") - ret0, _ := ret[0].(uint64) - return ret0 -} - -// GetSize indicates an expected call of GetSize. -func (mr *MockNetworkBufferMockRecorder) GetSize() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSize", reflect.TypeOf((*MockNetworkBuffer)(nil).GetSize)) -} - -// Prepend mocks base method. -func (m *MockNetworkBuffer) Prepend(data []byte) bool { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Prepend", data) - ret0, _ := ret[0].(bool) - return ret0 -} - -// Prepend indicates an expected call of Prepend. -func (mr *MockNetworkBufferMockRecorder) Prepend(data any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Prepend", reflect.TypeOf((*MockNetworkBuffer)(nil).Prepend), data) -} - -// MockNetworkFilterHandle is a mock of NetworkFilterHandle interface. -type MockNetworkFilterHandle struct { - ctrl *gomock.Controller - recorder *MockNetworkFilterHandleMockRecorder - isgomock struct{} -} - -// MockNetworkFilterHandleMockRecorder is the mock recorder for MockNetworkFilterHandle. -type MockNetworkFilterHandleMockRecorder struct { - mock *MockNetworkFilterHandle -} - -// NewMockNetworkFilterHandle creates a new mock instance. -func NewMockNetworkFilterHandle(ctrl *gomock.Controller) *MockNetworkFilterHandle { - mock := &MockNetworkFilterHandle{ctrl: ctrl} - mock.recorder = &MockNetworkFilterHandleMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockNetworkFilterHandle) EXPECT() *MockNetworkFilterHandleMockRecorder { - return m.recorder -} - -// AboveHighWatermark mocks base method. -func (m *MockNetworkFilterHandle) AboveHighWatermark() bool { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AboveHighWatermark") - ret0, _ := ret[0].(bool) - return ret0 -} - -// AboveHighWatermark indicates an expected call of AboveHighWatermark. -func (mr *MockNetworkFilterHandleMockRecorder) AboveHighWatermark() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AboveHighWatermark", reflect.TypeOf((*MockNetworkFilterHandle)(nil).AboveHighWatermark)) -} - -// Close mocks base method. -func (m *MockNetworkFilterHandle) Close(closeType shared.NetworkConnectionCloseType) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "Close", closeType) -} - -// Close indicates an expected call of Close. -func (mr *MockNetworkFilterHandleMockRecorder) Close(closeType any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockNetworkFilterHandle)(nil).Close), closeType) -} - -// CloseWithDetails mocks base method. -func (m *MockNetworkFilterHandle) CloseWithDetails(closeType shared.NetworkConnectionCloseType, details string) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "CloseWithDetails", closeType, details) -} - -// CloseWithDetails indicates an expected call of CloseWithDetails. -func (mr *MockNetworkFilterHandleMockRecorder) CloseWithDetails(closeType, details any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CloseWithDetails", reflect.TypeOf((*MockNetworkFilterHandle)(nil).CloseWithDetails), closeType, details) -} - -// ContinueReading mocks base method. -func (m *MockNetworkFilterHandle) ContinueReading() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "ContinueReading") -} - -// ContinueReading indicates an expected call of ContinueReading. -func (mr *MockNetworkFilterHandleMockRecorder) ContinueReading() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ContinueReading", reflect.TypeOf((*MockNetworkFilterHandle)(nil).ContinueReading)) -} - -// DecrementGaugeValue mocks base method. -func (m *MockNetworkFilterHandle) DecrementGaugeValue(id shared.MetricID, value uint64) shared.MetricsResult { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DecrementGaugeValue", id, value) - ret0, _ := ret[0].(shared.MetricsResult) - return ret0 -} - -// DecrementGaugeValue indicates an expected call of DecrementGaugeValue. -func (mr *MockNetworkFilterHandleMockRecorder) DecrementGaugeValue(id, value any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DecrementGaugeValue", reflect.TypeOf((*MockNetworkFilterHandle)(nil).DecrementGaugeValue), id, value) -} - -// DisableClose mocks base method. -func (m *MockNetworkFilterHandle) DisableClose(disabled bool) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "DisableClose", disabled) -} - -// DisableClose indicates an expected call of DisableClose. -func (mr *MockNetworkFilterHandleMockRecorder) DisableClose(disabled any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DisableClose", reflect.TypeOf((*MockNetworkFilterHandle)(nil).DisableClose), disabled) -} - -// EnableHalfClose mocks base method. -func (m *MockNetworkFilterHandle) EnableHalfClose(enabled bool) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "EnableHalfClose", enabled) -} - -// EnableHalfClose indicates an expected call of EnableHalfClose. -func (mr *MockNetworkFilterHandleMockRecorder) EnableHalfClose(enabled any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EnableHalfClose", reflect.TypeOf((*MockNetworkFilterHandle)(nil).EnableHalfClose), enabled) -} - -// GetBufferLimit mocks base method. -func (m *MockNetworkFilterHandle) GetBufferLimit() uint32 { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetBufferLimit") - ret0, _ := ret[0].(uint32) - return ret0 -} - -// GetBufferLimit indicates an expected call of GetBufferLimit. -func (mr *MockNetworkFilterHandleMockRecorder) GetBufferLimit() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBufferLimit", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetBufferLimit)) -} - -// GetClusterHostCounts mocks base method. -func (m *MockNetworkFilterHandle) GetClusterHostCounts(cluster string, priority uint32) (shared.ClusterHostCounts, bool) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetClusterHostCounts", cluster, priority) - ret0, _ := ret[0].(shared.ClusterHostCounts) - ret1, _ := ret[1].(bool) - return ret0, ret1 -} - -// GetClusterHostCounts indicates an expected call of GetClusterHostCounts. -func (mr *MockNetworkFilterHandleMockRecorder) GetClusterHostCounts(cluster, priority any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetClusterHostCounts", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetClusterHostCounts), cluster, priority) -} - -// GetConnectionID mocks base method. -func (m *MockNetworkFilterHandle) GetConnectionID() uint64 { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetConnectionID") - ret0, _ := ret[0].(uint64) - return ret0 -} - -// GetConnectionID indicates an expected call of GetConnectionID. -func (mr *MockNetworkFilterHandleMockRecorder) GetConnectionID() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetConnectionID", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetConnectionID)) -} - -// GetConnectionState mocks base method. -func (m *MockNetworkFilterHandle) GetConnectionState() shared.NetworkConnectionState { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetConnectionState") - ret0, _ := ret[0].(shared.NetworkConnectionState) - return ret0 -} - -// GetConnectionState indicates an expected call of GetConnectionState. -func (mr *MockNetworkFilterHandleMockRecorder) GetConnectionState() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetConnectionState", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetConnectionState)) -} - -// GetDirectRemoteAddress mocks base method. -func (m *MockNetworkFilterHandle) GetDirectRemoteAddress() (shared.UnsafeEnvoyBuffer, uint32, bool) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetDirectRemoteAddress") - ret0, _ := ret[0].(shared.UnsafeEnvoyBuffer) - ret1, _ := ret[1].(uint32) - ret2, _ := ret[2].(bool) - return ret0, ret1, ret2 -} - -// GetDirectRemoteAddress indicates an expected call of GetDirectRemoteAddress. -func (mr *MockNetworkFilterHandleMockRecorder) GetDirectRemoteAddress() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDirectRemoteAddress", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetDirectRemoteAddress)) -} - -// GetFilterState mocks base method. -func (m *MockNetworkFilterHandle) GetFilterState(key string) (shared.UnsafeEnvoyBuffer, bool) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetFilterState", key) - ret0, _ := ret[0].(shared.UnsafeEnvoyBuffer) - ret1, _ := ret[1].(bool) - return ret0, ret1 -} - -// GetFilterState indicates an expected call of GetFilterState. -func (mr *MockNetworkFilterHandleMockRecorder) GetFilterState(key any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFilterState", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetFilterState), key) -} - -// GetFilterStateTyped mocks base method. -func (m *MockNetworkFilterHandle) GetFilterStateTyped(key string) (shared.UnsafeEnvoyBuffer, bool) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetFilterStateTyped", key) - ret0, _ := ret[0].(shared.UnsafeEnvoyBuffer) - ret1, _ := ret[1].(bool) - return ret0, ret1 -} - -// GetFilterStateTyped indicates an expected call of GetFilterStateTyped. -func (mr *MockNetworkFilterHandleMockRecorder) GetFilterStateTyped(key any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFilterStateTyped", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetFilterStateTyped), key) -} - -// GetLocalAddress mocks base method. -func (m *MockNetworkFilterHandle) GetLocalAddress() (shared.UnsafeEnvoyBuffer, uint32, bool) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetLocalAddress") - ret0, _ := ret[0].(shared.UnsafeEnvoyBuffer) - ret1, _ := ret[1].(uint32) - ret2, _ := ret[2].(bool) - return ret0, ret1, ret2 -} - -// GetLocalAddress indicates an expected call of GetLocalAddress. -func (mr *MockNetworkFilterHandleMockRecorder) GetLocalAddress() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLocalAddress", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetLocalAddress)) -} - -// GetMetadataBool mocks base method. -func (m *MockNetworkFilterHandle) GetMetadataBool(metadataNamespace, key string) (bool, bool) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetMetadataBool", metadataNamespace, key) - ret0, _ := ret[0].(bool) - ret1, _ := ret[1].(bool) - return ret0, ret1 -} - -// GetMetadataBool indicates an expected call of GetMetadataBool. -func (mr *MockNetworkFilterHandleMockRecorder) GetMetadataBool(metadataNamespace, key any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMetadataBool", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetMetadataBool), metadataNamespace, key) -} - -// GetMetadataNumber mocks base method. -func (m *MockNetworkFilterHandle) GetMetadataNumber(metadataNamespace, key string) (float64, bool) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetMetadataNumber", metadataNamespace, key) - ret0, _ := ret[0].(float64) - ret1, _ := ret[1].(bool) - return ret0, ret1 -} - -// GetMetadataNumber indicates an expected call of GetMetadataNumber. -func (mr *MockNetworkFilterHandleMockRecorder) GetMetadataNumber(metadataNamespace, key any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMetadataNumber", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetMetadataNumber), metadataNamespace, key) -} - -// GetMetadataString mocks base method. -func (m *MockNetworkFilterHandle) GetMetadataString(metadataNamespace, key string) (shared.UnsafeEnvoyBuffer, bool) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetMetadataString", metadataNamespace, key) - ret0, _ := ret[0].(shared.UnsafeEnvoyBuffer) - ret1, _ := ret[1].(bool) - return ret0, ret1 -} - -// GetMetadataString indicates an expected call of GetMetadataString. -func (mr *MockNetworkFilterHandleMockRecorder) GetMetadataString(metadataNamespace, key any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMetadataString", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetMetadataString), metadataNamespace, key) -} - -// GetRemoteAddress mocks base method. -func (m *MockNetworkFilterHandle) GetRemoteAddress() (shared.UnsafeEnvoyBuffer, uint32, bool) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetRemoteAddress") - ret0, _ := ret[0].(shared.UnsafeEnvoyBuffer) - ret1, _ := ret[1].(uint32) - ret2, _ := ret[2].(bool) - return ret0, ret1, ret2 -} - -// GetRemoteAddress indicates an expected call of GetRemoteAddress. -func (mr *MockNetworkFilterHandleMockRecorder) GetRemoteAddress() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRemoteAddress", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetRemoteAddress)) -} - -// GetRequestedServerName mocks base method. -func (m *MockNetworkFilterHandle) GetRequestedServerName() (shared.UnsafeEnvoyBuffer, bool) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetRequestedServerName") - ret0, _ := ret[0].(shared.UnsafeEnvoyBuffer) - ret1, _ := ret[1].(bool) - return ret0, ret1 -} - -// GetRequestedServerName indicates an expected call of GetRequestedServerName. -func (mr *MockNetworkFilterHandleMockRecorder) GetRequestedServerName() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRequestedServerName", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetRequestedServerName)) -} - -// GetSSLDNSSANs mocks base method. -func (m *MockNetworkFilterHandle) GetSSLDNSSANs() []shared.UnsafeEnvoyBuffer { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetSSLDNSSANs") - ret0, _ := ret[0].([]shared.UnsafeEnvoyBuffer) - return ret0 -} - -// GetSSLDNSSANs indicates an expected call of GetSSLDNSSANs. -func (mr *MockNetworkFilterHandleMockRecorder) GetSSLDNSSANs() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSSLDNSSANs", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetSSLDNSSANs)) -} - -// GetSSLSubject mocks base method. -func (m *MockNetworkFilterHandle) GetSSLSubject() (shared.UnsafeEnvoyBuffer, bool) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetSSLSubject") - ret0, _ := ret[0].(shared.UnsafeEnvoyBuffer) - ret1, _ := ret[1].(bool) - return ret0, ret1 -} - -// GetSSLSubject indicates an expected call of GetSSLSubject. -func (mr *MockNetworkFilterHandleMockRecorder) GetSSLSubject() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSSLSubject", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetSSLSubject)) -} - -// GetSSLURISANs mocks base method. -func (m *MockNetworkFilterHandle) GetSSLURISANs() []shared.UnsafeEnvoyBuffer { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetSSLURISANs") - ret0, _ := ret[0].([]shared.UnsafeEnvoyBuffer) - return ret0 -} - -// GetSSLURISANs indicates an expected call of GetSSLURISANs. -func (mr *MockNetworkFilterHandleMockRecorder) GetSSLURISANs() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSSLURISANs", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetSSLURISANs)) -} - -// GetScheduler mocks base method. -func (m *MockNetworkFilterHandle) GetScheduler() shared.Scheduler { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetScheduler") - ret0, _ := ret[0].(shared.Scheduler) - return ret0 -} - -// GetScheduler indicates an expected call of GetScheduler. -func (mr *MockNetworkFilterHandleMockRecorder) GetScheduler() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetScheduler", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetScheduler)) -} - -// GetSocketOptionBytes mocks base method. -func (m *MockNetworkFilterHandle) GetSocketOptionBytes(level, name int64, state shared.SocketOptionState) (shared.UnsafeEnvoyBuffer, bool) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetSocketOptionBytes", level, name, state) - ret0, _ := ret[0].(shared.UnsafeEnvoyBuffer) - ret1, _ := ret[1].(bool) - return ret0, ret1 -} - -// GetSocketOptionBytes indicates an expected call of GetSocketOptionBytes. -func (mr *MockNetworkFilterHandleMockRecorder) GetSocketOptionBytes(level, name, state any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSocketOptionBytes", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetSocketOptionBytes), level, name, state) -} - -// GetSocketOptionInt mocks base method. -func (m *MockNetworkFilterHandle) GetSocketOptionInt(level, name int64, state shared.SocketOptionState) (int64, bool) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetSocketOptionInt", level, name, state) - ret0, _ := ret[0].(int64) - ret1, _ := ret[1].(bool) - return ret0, ret1 -} - -// GetSocketOptionInt indicates an expected call of GetSocketOptionInt. -func (mr *MockNetworkFilterHandleMockRecorder) GetSocketOptionInt(level, name, state any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSocketOptionInt", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetSocketOptionInt), level, name, state) -} - -// GetSocketOptions mocks base method. -func (m *MockNetworkFilterHandle) GetSocketOptions() []shared.SocketOption { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetSocketOptions") - ret0, _ := ret[0].([]shared.SocketOption) - return ret0 -} - -// GetSocketOptions indicates an expected call of GetSocketOptions. -func (mr *MockNetworkFilterHandleMockRecorder) GetSocketOptions() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSocketOptions", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetSocketOptions)) -} - -// GetUpstreamHostAddress mocks base method. -func (m *MockNetworkFilterHandle) GetUpstreamHostAddress() (shared.UnsafeEnvoyBuffer, uint32, bool) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetUpstreamHostAddress") - ret0, _ := ret[0].(shared.UnsafeEnvoyBuffer) - ret1, _ := ret[1].(uint32) - ret2, _ := ret[2].(bool) - return ret0, ret1, ret2 -} - -// GetUpstreamHostAddress indicates an expected call of GetUpstreamHostAddress. -func (mr *MockNetworkFilterHandleMockRecorder) GetUpstreamHostAddress() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUpstreamHostAddress", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetUpstreamHostAddress)) -} - -// GetUpstreamHostCluster mocks base method. -func (m *MockNetworkFilterHandle) GetUpstreamHostCluster() (shared.UnsafeEnvoyBuffer, bool) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetUpstreamHostCluster") - ret0, _ := ret[0].(shared.UnsafeEnvoyBuffer) - ret1, _ := ret[1].(bool) - return ret0, ret1 -} - -// GetUpstreamHostCluster indicates an expected call of GetUpstreamHostCluster. -func (mr *MockNetworkFilterHandleMockRecorder) GetUpstreamHostCluster() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUpstreamHostCluster", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetUpstreamHostCluster)) -} - -// GetUpstreamHostHostname mocks base method. -func (m *MockNetworkFilterHandle) GetUpstreamHostHostname() (shared.UnsafeEnvoyBuffer, bool) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetUpstreamHostHostname") - ret0, _ := ret[0].(shared.UnsafeEnvoyBuffer) - ret1, _ := ret[1].(bool) - return ret0, ret1 -} - -// GetUpstreamHostHostname indicates an expected call of GetUpstreamHostHostname. -func (mr *MockNetworkFilterHandleMockRecorder) GetUpstreamHostHostname() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUpstreamHostHostname", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetUpstreamHostHostname)) -} - -// GetWorkerIndex mocks base method. -func (m *MockNetworkFilterHandle) GetWorkerIndex() uint32 { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetWorkerIndex") - ret0, _ := ret[0].(uint32) - return ret0 -} - -// GetWorkerIndex indicates an expected call of GetWorkerIndex. -func (mr *MockNetworkFilterHandleMockRecorder) GetWorkerIndex() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkerIndex", reflect.TypeOf((*MockNetworkFilterHandle)(nil).GetWorkerIndex)) -} - -// HasUpstreamHost mocks base method. -func (m *MockNetworkFilterHandle) HasUpstreamHost() bool { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HasUpstreamHost") - ret0, _ := ret[0].(bool) - return ret0 -} - -// HasUpstreamHost indicates an expected call of HasUpstreamHost. -func (mr *MockNetworkFilterHandleMockRecorder) HasUpstreamHost() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasUpstreamHost", reflect.TypeOf((*MockNetworkFilterHandle)(nil).HasUpstreamHost)) -} - -// HttpCallout mocks base method. -func (m *MockNetworkFilterHandle) HttpCallout(cluster string, headers [][2]string, body []byte, timeoutMs uint64, cb shared.HttpCalloutCallback) (shared.HttpCalloutInitResult, uint64) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HttpCallout", cluster, headers, body, timeoutMs, cb) - ret0, _ := ret[0].(shared.HttpCalloutInitResult) - ret1, _ := ret[1].(uint64) - return ret0, ret1 -} - -// HttpCallout indicates an expected call of HttpCallout. -func (mr *MockNetworkFilterHandleMockRecorder) HttpCallout(cluster, headers, body, timeoutMs, cb any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HttpCallout", reflect.TypeOf((*MockNetworkFilterHandle)(nil).HttpCallout), cluster, headers, body, timeoutMs, cb) -} - -// IncrementCounterValue mocks base method. -func (m *MockNetworkFilterHandle) IncrementCounterValue(id shared.MetricID, value uint64) shared.MetricsResult { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IncrementCounterValue", id, value) - ret0, _ := ret[0].(shared.MetricsResult) - return ret0 -} - -// IncrementCounterValue indicates an expected call of IncrementCounterValue. -func (mr *MockNetworkFilterHandleMockRecorder) IncrementCounterValue(id, value any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IncrementCounterValue", reflect.TypeOf((*MockNetworkFilterHandle)(nil).IncrementCounterValue), id, value) -} - -// IncrementGaugeValue mocks base method. -func (m *MockNetworkFilterHandle) IncrementGaugeValue(id shared.MetricID, value uint64) shared.MetricsResult { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IncrementGaugeValue", id, value) - ret0, _ := ret[0].(shared.MetricsResult) - return ret0 -} - -// IncrementGaugeValue indicates an expected call of IncrementGaugeValue. -func (mr *MockNetworkFilterHandleMockRecorder) IncrementGaugeValue(id, value any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IncrementGaugeValue", reflect.TypeOf((*MockNetworkFilterHandle)(nil).IncrementGaugeValue), id, value) -} - -// InjectReadData mocks base method. -func (m *MockNetworkFilterHandle) InjectReadData(data []byte, endStream bool) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "InjectReadData", data, endStream) -} - -// InjectReadData indicates an expected call of InjectReadData. -func (mr *MockNetworkFilterHandleMockRecorder) InjectReadData(data, endStream any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InjectReadData", reflect.TypeOf((*MockNetworkFilterHandle)(nil).InjectReadData), data, endStream) -} - -// InjectWriteData mocks base method. -func (m *MockNetworkFilterHandle) InjectWriteData(data []byte, endStream bool) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "InjectWriteData", data, endStream) -} - -// InjectWriteData indicates an expected call of InjectWriteData. -func (mr *MockNetworkFilterHandleMockRecorder) InjectWriteData(data, endStream any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InjectWriteData", reflect.TypeOf((*MockNetworkFilterHandle)(nil).InjectWriteData), data, endStream) -} - -// IsHalfCloseEnabled mocks base method. -func (m *MockNetworkFilterHandle) IsHalfCloseEnabled() bool { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IsHalfCloseEnabled") - ret0, _ := ret[0].(bool) - return ret0 -} - -// IsHalfCloseEnabled indicates an expected call of IsHalfCloseEnabled. -func (mr *MockNetworkFilterHandleMockRecorder) IsHalfCloseEnabled() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsHalfCloseEnabled", reflect.TypeOf((*MockNetworkFilterHandle)(nil).IsHalfCloseEnabled)) -} - -// IsSSL mocks base method. -func (m *MockNetworkFilterHandle) IsSSL() bool { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IsSSL") - ret0, _ := ret[0].(bool) - return ret0 -} - -// IsSSL indicates an expected call of IsSSL. -func (mr *MockNetworkFilterHandleMockRecorder) IsSSL() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsSSL", reflect.TypeOf((*MockNetworkFilterHandle)(nil).IsSSL)) -} - -// Log mocks base method. -func (m *MockNetworkFilterHandle) Log(level shared.LogLevel, format string, args ...any) { - m.ctrl.T.Helper() - varargs := []any{level, format} - for _, a := range args { - varargs = append(varargs, a) - } - m.ctrl.Call(m, "Log", varargs...) -} - -// Log indicates an expected call of Log. -func (mr *MockNetworkFilterHandleMockRecorder) Log(level, format any, args ...any) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]any{level, format}, args...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Log", reflect.TypeOf((*MockNetworkFilterHandle)(nil).Log), varargs...) -} - -// ReadBuffer mocks base method. -func (m *MockNetworkFilterHandle) ReadBuffer() shared.NetworkBuffer { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ReadBuffer") - ret0, _ := ret[0].(shared.NetworkBuffer) - return ret0 -} - -// ReadBuffer indicates an expected call of ReadBuffer. -func (mr *MockNetworkFilterHandleMockRecorder) ReadBuffer() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadBuffer", reflect.TypeOf((*MockNetworkFilterHandle)(nil).ReadBuffer)) -} - -// ReadDisable mocks base method. -func (m *MockNetworkFilterHandle) ReadDisable(disable bool) shared.NetworkReadDisableStatus { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ReadDisable", disable) - ret0, _ := ret[0].(shared.NetworkReadDisableStatus) - return ret0 -} - -// ReadDisable indicates an expected call of ReadDisable. -func (mr *MockNetworkFilterHandleMockRecorder) ReadDisable(disable any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadDisable", reflect.TypeOf((*MockNetworkFilterHandle)(nil).ReadDisable), disable) -} - -// ReadEnabled mocks base method. -func (m *MockNetworkFilterHandle) ReadEnabled() bool { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ReadEnabled") - ret0, _ := ret[0].(bool) - return ret0 -} - -// ReadEnabled indicates an expected call of ReadEnabled. -func (mr *MockNetworkFilterHandleMockRecorder) ReadEnabled() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadEnabled", reflect.TypeOf((*MockNetworkFilterHandle)(nil).ReadEnabled)) -} - -// RecordHistogramValue mocks base method. -func (m *MockNetworkFilterHandle) RecordHistogramValue(id shared.MetricID, value uint64) shared.MetricsResult { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RecordHistogramValue", id, value) - ret0, _ := ret[0].(shared.MetricsResult) - return ret0 -} - -// RecordHistogramValue indicates an expected call of RecordHistogramValue. -func (mr *MockNetworkFilterHandleMockRecorder) RecordHistogramValue(id, value any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordHistogramValue", reflect.TypeOf((*MockNetworkFilterHandle)(nil).RecordHistogramValue), id, value) -} - -// SetBufferLimits mocks base method. -func (m *MockNetworkFilterHandle) SetBufferLimits(limit uint32) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetBufferLimits", limit) -} - -// SetBufferLimits indicates an expected call of SetBufferLimits. -func (mr *MockNetworkFilterHandleMockRecorder) SetBufferLimits(limit any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetBufferLimits", reflect.TypeOf((*MockNetworkFilterHandle)(nil).SetBufferLimits), limit) -} - -// SetFilterState mocks base method. -func (m *MockNetworkFilterHandle) SetFilterState(key string, value []byte) bool { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SetFilterState", key, value) - ret0, _ := ret[0].(bool) - return ret0 -} - -// SetFilterState indicates an expected call of SetFilterState. -func (mr *MockNetworkFilterHandleMockRecorder) SetFilterState(key, value any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFilterState", reflect.TypeOf((*MockNetworkFilterHandle)(nil).SetFilterState), key, value) -} - -// SetFilterStateTyped mocks base method. -func (m *MockNetworkFilterHandle) SetFilterStateTyped(key string, value []byte) bool { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SetFilterStateTyped", key, value) - ret0, _ := ret[0].(bool) - return ret0 -} - -// SetFilterStateTyped indicates an expected call of SetFilterStateTyped. -func (mr *MockNetworkFilterHandleMockRecorder) SetFilterStateTyped(key, value any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFilterStateTyped", reflect.TypeOf((*MockNetworkFilterHandle)(nil).SetFilterStateTyped), key, value) -} - -// SetGaugeValue mocks base method. -func (m *MockNetworkFilterHandle) SetGaugeValue(id shared.MetricID, value uint64) shared.MetricsResult { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SetGaugeValue", id, value) - ret0, _ := ret[0].(shared.MetricsResult) - return ret0 -} - -// SetGaugeValue indicates an expected call of SetGaugeValue. -func (mr *MockNetworkFilterHandleMockRecorder) SetGaugeValue(id, value any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetGaugeValue", reflect.TypeOf((*MockNetworkFilterHandle)(nil).SetGaugeValue), id, value) -} - -// SetMetadata mocks base method. -func (m *MockNetworkFilterHandle) SetMetadata(metadataNamespace, key string, value any) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetMetadata", metadataNamespace, key, value) -} - -// SetMetadata indicates an expected call of SetMetadata. -func (mr *MockNetworkFilterHandleMockRecorder) SetMetadata(metadataNamespace, key, value any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetMetadata", reflect.TypeOf((*MockNetworkFilterHandle)(nil).SetMetadata), metadataNamespace, key, value) -} - -// SetSocketOptionBytes mocks base method. -func (m *MockNetworkFilterHandle) SetSocketOptionBytes(level, name int64, state shared.SocketOptionState, value []byte) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetSocketOptionBytes", level, name, state, value) -} - -// SetSocketOptionBytes indicates an expected call of SetSocketOptionBytes. -func (mr *MockNetworkFilterHandleMockRecorder) SetSocketOptionBytes(level, name, state, value any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSocketOptionBytes", reflect.TypeOf((*MockNetworkFilterHandle)(nil).SetSocketOptionBytes), level, name, state, value) -} - -// SetSocketOptionInt mocks base method. -func (m *MockNetworkFilterHandle) SetSocketOptionInt(level, name int64, state shared.SocketOptionState, value int64) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetSocketOptionInt", level, name, state, value) -} - -// SetSocketOptionInt indicates an expected call of SetSocketOptionInt. -func (mr *MockNetworkFilterHandleMockRecorder) SetSocketOptionInt(level, name, state, value any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSocketOptionInt", reflect.TypeOf((*MockNetworkFilterHandle)(nil).SetSocketOptionInt), level, name, state, value) -} - -// StartUpstreamSecureTransport mocks base method. -func (m *MockNetworkFilterHandle) StartUpstreamSecureTransport() bool { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "StartUpstreamSecureTransport") - ret0, _ := ret[0].(bool) - return ret0 -} - -// StartUpstreamSecureTransport indicates an expected call of StartUpstreamSecureTransport. -func (mr *MockNetworkFilterHandleMockRecorder) StartUpstreamSecureTransport() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartUpstreamSecureTransport", reflect.TypeOf((*MockNetworkFilterHandle)(nil).StartUpstreamSecureTransport)) -} - -// Write mocks base method. -func (m *MockNetworkFilterHandle) Write(data []byte, endStream bool) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "Write", data, endStream) -} - -// Write indicates an expected call of Write. -func (mr *MockNetworkFilterHandleMockRecorder) Write(data, endStream any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Write", reflect.TypeOf((*MockNetworkFilterHandle)(nil).Write), data, endStream) -} - -// WriteBuffer mocks base method. -func (m *MockNetworkFilterHandle) WriteBuffer() shared.NetworkBuffer { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "WriteBuffer") - ret0, _ := ret[0].(shared.NetworkBuffer) - return ret0 -} - -// WriteBuffer indicates an expected call of WriteBuffer. -func (mr *MockNetworkFilterHandleMockRecorder) WriteBuffer() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WriteBuffer", reflect.TypeOf((*MockNetworkFilterHandle)(nil).WriteBuffer)) -} - -// MockNetworkFilterConfigHandle is a mock of NetworkFilterConfigHandle interface. -type MockNetworkFilterConfigHandle struct { - ctrl *gomock.Controller - recorder *MockNetworkFilterConfigHandleMockRecorder - isgomock struct{} -} - -// MockNetworkFilterConfigHandleMockRecorder is the mock recorder for MockNetworkFilterConfigHandle. -type MockNetworkFilterConfigHandleMockRecorder struct { - mock *MockNetworkFilterConfigHandle -} - -// NewMockNetworkFilterConfigHandle creates a new mock instance. -func NewMockNetworkFilterConfigHandle(ctrl *gomock.Controller) *MockNetworkFilterConfigHandle { - mock := &MockNetworkFilterConfigHandle{ctrl: ctrl} - mock.recorder = &MockNetworkFilterConfigHandleMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockNetworkFilterConfigHandle) EXPECT() *MockNetworkFilterConfigHandleMockRecorder { - return m.recorder -} - -// DefineCounter mocks base method. -func (m *MockNetworkFilterConfigHandle) DefineCounter(name string) (shared.MetricID, shared.MetricsResult) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DefineCounter", name) - ret0, _ := ret[0].(shared.MetricID) - ret1, _ := ret[1].(shared.MetricsResult) - return ret0, ret1 -} - -// DefineCounter indicates an expected call of DefineCounter. -func (mr *MockNetworkFilterConfigHandleMockRecorder) DefineCounter(name any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefineCounter", reflect.TypeOf((*MockNetworkFilterConfigHandle)(nil).DefineCounter), name) -} - -// DefineGauge mocks base method. -func (m *MockNetworkFilterConfigHandle) DefineGauge(name string) (shared.MetricID, shared.MetricsResult) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DefineGauge", name) - ret0, _ := ret[0].(shared.MetricID) - ret1, _ := ret[1].(shared.MetricsResult) - return ret0, ret1 -} - -// DefineGauge indicates an expected call of DefineGauge. -func (mr *MockNetworkFilterConfigHandleMockRecorder) DefineGauge(name any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefineGauge", reflect.TypeOf((*MockNetworkFilterConfigHandle)(nil).DefineGauge), name) -} - -// DefineHistogram mocks base method. -func (m *MockNetworkFilterConfigHandle) DefineHistogram(name string) (shared.MetricID, shared.MetricsResult) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DefineHistogram", name) - ret0, _ := ret[0].(shared.MetricID) - ret1, _ := ret[1].(shared.MetricsResult) - return ret0, ret1 -} - -// DefineHistogram indicates an expected call of DefineHistogram. -func (mr *MockNetworkFilterConfigHandleMockRecorder) DefineHistogram(name any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefineHistogram", reflect.TypeOf((*MockNetworkFilterConfigHandle)(nil).DefineHistogram), name) -} - -// GetScheduler mocks base method. -func (m *MockNetworkFilterConfigHandle) GetScheduler() shared.Scheduler { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetScheduler") - ret0, _ := ret[0].(shared.Scheduler) - return ret0 -} - -// GetScheduler indicates an expected call of GetScheduler. -func (mr *MockNetworkFilterConfigHandleMockRecorder) GetScheduler() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetScheduler", reflect.TypeOf((*MockNetworkFilterConfigHandle)(nil).GetScheduler)) -} - -// Log mocks base method. -func (m *MockNetworkFilterConfigHandle) Log(level shared.LogLevel, format string, args ...any) { - m.ctrl.T.Helper() - varargs := []any{level, format} - for _, a := range args { - varargs = append(varargs, a) - } - m.ctrl.Call(m, "Log", varargs...) -} - -// Log indicates an expected call of Log. -func (mr *MockNetworkFilterConfigHandleMockRecorder) Log(level, format any, args ...any) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]any{level, format}, args...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Log", reflect.TypeOf((*MockNetworkFilterConfigHandle)(nil).Log), varargs...) -} diff --git a/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_types.go b/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_types.go deleted file mode 100644 index 67d300e5ba4d7..0000000000000 --- a/source/extensions/dynamic_modules/sdk/go/shared/mocks/mock_types.go +++ /dev/null @@ -1,173 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: types.go -// -// Generated by this command: -// -// mockgen -source=types.go -destination=mocks/mock_types.go -package=mocks -// - -// Package mocks is a generated GoMock package. -package mocks - -import ( - reflect "reflect" - - shared "github.com/envoyproxy/envoy/source/extensions/dynamic_modules/sdk/go/shared" - gomock "go.uber.org/mock/gomock" -) - -// MockHttpCalloutCallback is a mock of HttpCalloutCallback interface. -type MockHttpCalloutCallback struct { - ctrl *gomock.Controller - recorder *MockHttpCalloutCallbackMockRecorder - isgomock struct{} -} - -// MockHttpCalloutCallbackMockRecorder is the mock recorder for MockHttpCalloutCallback. -type MockHttpCalloutCallbackMockRecorder struct { - mock *MockHttpCalloutCallback -} - -// NewMockHttpCalloutCallback creates a new mock instance. -func NewMockHttpCalloutCallback(ctrl *gomock.Controller) *MockHttpCalloutCallback { - mock := &MockHttpCalloutCallback{ctrl: ctrl} - mock.recorder = &MockHttpCalloutCallbackMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockHttpCalloutCallback) EXPECT() *MockHttpCalloutCallbackMockRecorder { - return m.recorder -} - -// OnHttpCalloutDone mocks base method. -func (m *MockHttpCalloutCallback) OnHttpCalloutDone(calloutID uint64, result shared.HttpCalloutResult, headers [][2]shared.UnsafeEnvoyBuffer, body []shared.UnsafeEnvoyBuffer) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "OnHttpCalloutDone", calloutID, result, headers, body) -} - -// OnHttpCalloutDone indicates an expected call of OnHttpCalloutDone. -func (mr *MockHttpCalloutCallbackMockRecorder) OnHttpCalloutDone(calloutID, result, headers, body any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnHttpCalloutDone", reflect.TypeOf((*MockHttpCalloutCallback)(nil).OnHttpCalloutDone), calloutID, result, headers, body) -} - -// MockHttpStreamCallback is a mock of HttpStreamCallback interface. -type MockHttpStreamCallback struct { - ctrl *gomock.Controller - recorder *MockHttpStreamCallbackMockRecorder - isgomock struct{} -} - -// MockHttpStreamCallbackMockRecorder is the mock recorder for MockHttpStreamCallback. -type MockHttpStreamCallbackMockRecorder struct { - mock *MockHttpStreamCallback -} - -// NewMockHttpStreamCallback creates a new mock instance. -func NewMockHttpStreamCallback(ctrl *gomock.Controller) *MockHttpStreamCallback { - mock := &MockHttpStreamCallback{ctrl: ctrl} - mock.recorder = &MockHttpStreamCallbackMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockHttpStreamCallback) EXPECT() *MockHttpStreamCallbackMockRecorder { - return m.recorder -} - -// OnHttpStreamComplete mocks base method. -func (m *MockHttpStreamCallback) OnHttpStreamComplete(streamID uint64) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "OnHttpStreamComplete", streamID) -} - -// OnHttpStreamComplete indicates an expected call of OnHttpStreamComplete. -func (mr *MockHttpStreamCallbackMockRecorder) OnHttpStreamComplete(streamID any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnHttpStreamComplete", reflect.TypeOf((*MockHttpStreamCallback)(nil).OnHttpStreamComplete), streamID) -} - -// OnHttpStreamData mocks base method. -func (m *MockHttpStreamCallback) OnHttpStreamData(streamID uint64, body []shared.UnsafeEnvoyBuffer, endStream bool) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "OnHttpStreamData", streamID, body, endStream) -} - -// OnHttpStreamData indicates an expected call of OnHttpStreamData. -func (mr *MockHttpStreamCallbackMockRecorder) OnHttpStreamData(streamID, body, endStream any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnHttpStreamData", reflect.TypeOf((*MockHttpStreamCallback)(nil).OnHttpStreamData), streamID, body, endStream) -} - -// OnHttpStreamHeaders mocks base method. -func (m *MockHttpStreamCallback) OnHttpStreamHeaders(streamID uint64, headers [][2]shared.UnsafeEnvoyBuffer, endStream bool) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "OnHttpStreamHeaders", streamID, headers, endStream) -} - -// OnHttpStreamHeaders indicates an expected call of OnHttpStreamHeaders. -func (mr *MockHttpStreamCallbackMockRecorder) OnHttpStreamHeaders(streamID, headers, endStream any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnHttpStreamHeaders", reflect.TypeOf((*MockHttpStreamCallback)(nil).OnHttpStreamHeaders), streamID, headers, endStream) -} - -// OnHttpStreamReset mocks base method. -func (m *MockHttpStreamCallback) OnHttpStreamReset(streamID uint64, reason shared.HttpStreamResetReason) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "OnHttpStreamReset", streamID, reason) -} - -// OnHttpStreamReset indicates an expected call of OnHttpStreamReset. -func (mr *MockHttpStreamCallbackMockRecorder) OnHttpStreamReset(streamID, reason any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnHttpStreamReset", reflect.TypeOf((*MockHttpStreamCallback)(nil).OnHttpStreamReset), streamID, reason) -} - -// OnHttpStreamTrailers mocks base method. -func (m *MockHttpStreamCallback) OnHttpStreamTrailers(streamID uint64, trailers [][2]shared.UnsafeEnvoyBuffer) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "OnHttpStreamTrailers", streamID, trailers) -} - -// OnHttpStreamTrailers indicates an expected call of OnHttpStreamTrailers. -func (mr *MockHttpStreamCallbackMockRecorder) OnHttpStreamTrailers(streamID, trailers any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnHttpStreamTrailers", reflect.TypeOf((*MockHttpStreamCallback)(nil).OnHttpStreamTrailers), streamID, trailers) -} - -// MockScheduler is a mock of Scheduler interface. -type MockScheduler struct { - ctrl *gomock.Controller - recorder *MockSchedulerMockRecorder - isgomock struct{} -} - -// MockSchedulerMockRecorder is the mock recorder for MockScheduler. -type MockSchedulerMockRecorder struct { - mock *MockScheduler -} - -// NewMockScheduler creates a new mock instance. -func NewMockScheduler(ctrl *gomock.Controller) *MockScheduler { - mock := &MockScheduler{ctrl: ctrl} - mock.recorder = &MockSchedulerMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockScheduler) EXPECT() *MockSchedulerMockRecorder { - return m.recorder -} - -// Schedule mocks base method. -func (m *MockScheduler) Schedule(arg0 func()) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "Schedule", arg0) -} - -// Schedule indicates an expected call of Schedule. -func (mr *MockSchedulerMockRecorder) Schedule(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Schedule", reflect.TypeOf((*MockScheduler)(nil).Schedule), arg0) -} diff --git a/source/extensions/dynamic_modules/sdk/go/shared/network_api.go b/source/extensions/dynamic_modules/sdk/go/shared/network_api.go index 3d6342ccf5ea3..4d8d696973520 100644 --- a/source/extensions/dynamic_modules/sdk/go/shared/network_api.go +++ b/source/extensions/dynamic_modules/sdk/go/shared/network_api.go @@ -1,4 +1,3 @@ -//go:generate mockgen -source=network_api.go -destination=mocks/mock_network_api.go -package=mocks package shared // NetworkFilter is the interface to implement your own network filter logic. diff --git a/source/extensions/dynamic_modules/sdk/go/shared/network_base.go b/source/extensions/dynamic_modules/sdk/go/shared/network_base.go index 018a22ed5a292..7133012e4fda3 100644 --- a/source/extensions/dynamic_modules/sdk/go/shared/network_base.go +++ b/source/extensions/dynamic_modules/sdk/go/shared/network_base.go @@ -1,4 +1,3 @@ -//go:generate mockgen -source=network_base.go -destination=mocks/mock_network_base.go -package=mocks package shared // NetworkBuffer is an interface that provides access to the read and write buffers of a network diff --git a/source/extensions/dynamic_modules/sdk/go/shared/types.go b/source/extensions/dynamic_modules/sdk/go/shared/types.go deleted file mode 100644 index bf28c4c76fcfe..0000000000000 --- a/source/extensions/dynamic_modules/sdk/go/shared/types.go +++ /dev/null @@ -1,336 +0,0 @@ -//go:generate mockgen -source=types.go -destination=mocks/mock_types.go -package=mocks -package shared - -import ( - "strings" - "unsafe" -) - -// Cross-surface types and interfaces shared by multiple SDK surfaces (HTTP filter, network -// filter, listener filter, access logger, etc.). Surface-specific types live in their own -// files (http.go for HTTP, network.go for network, and so on). - -// UnsafeEnvoyBuffer is a struct that represents a buffer of data from Envoy. -// It contains a pointer to the data and its length. The memory of the data is managed by Envoy. -type UnsafeEnvoyBuffer struct { - // Pointer to the start of the buffer data. - Ptr *byte - // Length of the buffer data in bytes. - Len uint64 -} - -func (b UnsafeEnvoyBuffer) ToUnsafeBytes() []byte { - if b.Ptr == nil || b.Len == 0 { - return nil - } - // Use unsafe to create a byte slice that points to the buffer data without copying. - return unsafe.Slice(b.Ptr, b.Len) -} - -// ToBytes converts the UnsafeEnvoyBuffer to a byte slice. It creates a copy of the data in Go memory. -func (b UnsafeEnvoyBuffer) ToBytes() []byte { - if b.Ptr == nil || b.Len == 0 { - return nil - } - // Create a byte slice that copys the data from the buffer. - owned := make([]byte, b.Len) - // Use unsafe to copy the data from the buffer to the byte slice. - src := unsafe.Slice(b.Ptr, b.Len) - copy(owned, src) - return owned -} - -func (b UnsafeEnvoyBuffer) ToUnsafeString() string { - if b.Ptr == nil || b.Len == 0 { - return "" - } - // Use unsafe to create a string that points to the buffer data without copying. - return unsafe.String(b.Ptr, b.Len) -} - -func (b UnsafeEnvoyBuffer) ToString() string { - if b.Ptr == nil || b.Len == 0 { - return "" - } - return strings.Clone(b.ToUnsafeString()) -} - -// LogLevel is the log level for messages logged via the host environment's logging mechanism. -type LogLevel uint32 - -const ( - LogLevelTrace LogLevel = iota - LogLevelDebug - LogLevelInfo - LogLevelWarn - LogLevelError - LogLevelCritical - LogLevelOff -) - -// MetricID is an opaque identifier for a metric defined via Define{Counter,Gauge,Histogram}. -type MetricID uint64 - -// MetricsResult is the result of a metric definition or update operation. -type MetricsResult uint32 - -const ( - MetricsSuccess MetricsResult = iota - MetricsNotFound - MetricsInvalidTags - MetricsFrozen -) - -// AttributeID identifies an attribute of the current request, response, connection, or upstream -// host that can be retrieved via Get{Attribute,...} family of methods. Corresponds to -// envoy_dynamic_module_type_attribute_id. -type AttributeID uint32 - -const ( - // request.path - AttributeIDRequestPath AttributeID = iota - // request.url_path - AttributeIDRequestUrlPath - // request.host - AttributeIDRequestHost - // request.scheme - AttributeIDRequestScheme - // request.method - AttributeIDRequestMethod - // request.headers - AttributeIDRequestHeaders - // request.referer - AttributeIDRequestReferer - // request.useragent - AttributeIDRequestUserAgent - // request.time - AttributeIDRequestTime - // request.id - AttributeIDRequestId - // request.protocol - AttributeIDRequestProtocol - // request.query - AttributeIDRequestQuery - // request.duration - AttributeIDRequestDuration - // request.size - AttributeIDRequestSize - // request.total_size - AttributeIDRequestTotalSize - // response.code - AttributeIDResponseCode - // response.code_details - AttributeIDResponseCodeDetails - // response.flags - AttributeIDResponseFlags - // response.grpc_status - AttributeIDResponseGrpcStatus - // response.headers - AttributeIDResponseHeaders - // response.trailers - AttributeIDResponseTrailers - // response.size - AttributeIDResponseSize - // response.total_size - AttributeIDResponseTotalSize - // response.backend_latency - AttributeIDResponseBackendLatency - // source.address - AttributeIDSourceAddress - // source.port - AttributeIDSourcePort - // destination.address - AttributeIDDestinationAddress - // destination.port - AttributeIDDestinationPort - // connection.id - AttributeIDConnectionId - // connection.mtls - AttributeIDConnectionMTLS - // connection.requested_server_name - AttributeIDConnectionRequestedServerName - // connection.tls_version - AttributeIDConnectionTLSVersion - // connection.subject_local_certificate - AttributeIDConnectionSubjectLocalCertificate - // connection.subject_peer_certificate - AttributeIDConnectionSubjectPeerCertificate - // connection.dns_san_local_certificate - AttributeIDConnectionDNSSanLocalCertificate - // connection.dns_san_peer_certificate - AttributeIDConnectionDNSSanPeerCertificate - // connection.uri_san_local_certificate - AttributeIDConnectionURISanLocalCertificate - // connection.uri_san_peer_certificate - AttributeIDConnectionURISanPeerCertificate - // connection.sha256_peer_certificate_digest - AttributeIDConnectionSha256PeerCertificateDigest - // connection.transport_failure_reason - AttributeIDConnectionTransportFailureReason - // connection.termination_details - AttributeIDConnectionTerminationDetails - // upstream.address - AttributeIDUpstreamAddress - // upstream.port - AttributeIDUpstreamPort - // upstream.tls_version - AttributeIDUpstreamTLSVersion - // upstream.subject_local_certificate - AttributeIDUpstreamSubjectLocalCertificate - // upstream.subject_peer_certificate - AttributeIDUpstreamSubjectPeerCertificate - // upstream.dns_san_local_certificate - AttributeIDUpstreamDNSSanLocalCertificate - // upstream.dns_san_peer_certificate - AttributeIDUpstreamDNSSanPeerCertificate - // upstream.uri_san_local_certificate - AttributeIDUpstreamURISanLocalCertificate - // upstream.uri_san_peer_certificate - AttributeIDUpstreamURISanPeerCertificate - // upstream.sha256_peer_certificate_digest - AttributeIDUpstreamSha256PeerCertificateDigest - // upstream.local_address - AttributeIDUpstreamLocalAddress - // upstream.transport_failure_reason - AttributeIDUpstreamTransportFailureReason - // upstream.request_attempt_count - AttributeIDUpstreamRequestAttemptCount - // upstream.cx_pool_ready_duration - AttributeIDUpstreamCxPoolReadyDuration - // upstream.locality - AttributeIDUpstreamLocality - // xds.node - AttributeIDXdsNode - // xds.cluster_name - AttributeIDXdsClusterName - // xds.cluster_metadata - AttributeIDXdsClusterMetadata - // xds.listener_direction - AttributeIDXdsListenerDirection - // xds.listener_metadata - AttributeIDXdsListenerMetadata - // xds.route_name - AttributeIDXdsRouteName - // xds.route_metadata - AttributeIDXdsRouteMetadata - // xds.virtual_host_name - AttributeIDXdsVirtualHostName - // xds.virtual_host_metadata - AttributeIDXdsVirtualHostMetadata - // xds.upstream_host_metadata - AttributeIDXdsUpstreamHostMetadata - // xds.filter_chain_name - AttributeIDXdsFilterChainName - // health_check - AttributeIDHealthCheck -) - -// HttpHeaderType identifies which HTTP header map to access. It corresponds to -// envoy_dynamic_module_type_http_header_type. The values match the ABI's enum order: -// RequestHeader, RequestTrailer, ResponseHeader, ResponseTrailer. -type HttpHeaderType uint32 - -const ( - HttpHeaderTypeRequestHeader HttpHeaderType = 0 - HttpHeaderTypeRequestTrailer HttpHeaderType = 1 - HttpHeaderTypeResponseHeader HttpHeaderType = 2 - HttpHeaderTypeResponseTrailer HttpHeaderType = 3 -) - -// HttpCalloutInitResult is the result of initializing an HTTP callout or stream. -type HttpCalloutInitResult uint32 - -const ( - HttpCalloutInitSuccess HttpCalloutInitResult = iota - HttpCalloutInitMissingRequiredHeaders - HttpCalloutInitClusterNotFound - HttpCalloutInitDuplicateCalloutId - HttpCalloutInitCannotCreateRequest -) - -// HttpCalloutResult is the result of a completed HTTP callout (delivered via -// HttpCalloutCallback.OnHttpCalloutDone). -type HttpCalloutResult uint32 - -const ( - HttpCalloutSuccess HttpCalloutResult = iota - HttpCalloutReset - HttpCalloutExceedResponseBufferLimit -) - -// HttpCalloutCallback is the callback interface invoked when an HTTP callout completes. -type HttpCalloutCallback interface { - OnHttpCalloutDone(calloutID uint64, result HttpCalloutResult, - headers [][2]UnsafeEnvoyBuffer, body []UnsafeEnvoyBuffer) -} - -// HttpStreamResetReason is the reason that an HTTP stream (started via StartHttpStream) -// was reset. -type HttpStreamResetReason uint32 - -const ( - HttpStreamResetReasonConnectionFailure HttpStreamResetReason = iota - HttpStreamResetReasonConnectionTermination - HttpStreamResetReasonLocalReset - HttpStreamResetReasonLocalRefusedStreamReset - HttpStreamResetReasonOverflow - HttpStreamResetReasonRemoteReset - HttpStreamResetReasonRemoteRefusedStreamReset - HttpStreamResetReasonProtocolError -) - -// HttpStreamCallback is the callback interface invoked for events on an HTTP stream started -// via StartHttpStream. -type HttpStreamCallback interface { - OnHttpStreamHeaders(streamID uint64, headers [][2]UnsafeEnvoyBuffer, endStream bool) - OnHttpStreamData(streamID uint64, body []UnsafeEnvoyBuffer, endStream bool) - OnHttpStreamTrailers(streamID uint64, trailers [][2]UnsafeEnvoyBuffer) - OnHttpStreamComplete(streamID uint64) - OnHttpStreamReset(streamID uint64, reason HttpStreamResetReason) -} - -// SocketOptionState represents the socket state at which an option should be applied. -// This corresponds to envoy_dynamic_module_type_socket_option_state in the dynamic module ABI. -type SocketOptionState uint32 - -const ( - // SocketOptionStatePrebind applies the option before the socket is bound. - SocketOptionStatePrebind SocketOptionState = iota - // SocketOptionStateBound applies the option after the socket is bound. - SocketOptionStateBound - // SocketOptionStateListening applies the option after the socket starts listening. - SocketOptionStateListening -) - -// SocketDirection represents whether the socket option should be applied to the upstream -// (outgoing to backend) or downstream (incoming from client) connection. -// This corresponds to envoy_dynamic_module_type_socket_direction in the dynamic module ABI. -type SocketDirection uint32 - -const ( - // SocketDirectionUpstream applies the option to the upstream (outgoing) connection. - SocketDirectionUpstream SocketDirection = iota - // SocketDirectionDownstream applies the option to the downstream (incoming) connection. - SocketDirectionDownstream -) - -// ClusterHostCounts carries the host counts returned by HttpFilterHandle.GetClusterHostCounts. -type ClusterHostCounts struct { - // Total is the total number of hosts in the priority set. - Total uint64 - // Healthy is the number of hosts in the HEALTHY state. - Healthy uint64 - // Degraded is the number of hosts in the DEGRADED state. - Degraded uint64 -} - -// Scheduler is the interface that provides scheduling capabilities for asynchronous operations. -// This allow the plugins run tasks in another thread and continue the processing later at the -// thread where the stream plugin is being processed. -type Scheduler interface { - // Schedule schedules a function to be executed asynchronously in the thread where the stream - // plugin is being processed. - // - // NOTE: The function may be ignored if the related plugin processing is completed. - Schedule(func()) -} From c68db1202ede2a2b5907e7183d069191bce1c15e Mon Sep 17 00:00:00 2001 From: Adam Anderson <6754028+AdamEAnderson@users.noreply.github.com> Date: Tue, 19 May 2026 23:18:19 +0000 Subject: [PATCH 5/5] fix format Signed-off-by: Adam Anderson <6754028+AdamEAnderson@users.noreply.github.com> --- source/extensions/dynamic_modules/sdk/go/abi/http.go | 2 +- source/extensions/dynamic_modules/sdk/go/abi/scheduler.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/extensions/dynamic_modules/sdk/go/abi/http.go b/source/extensions/dynamic_modules/sdk/go/abi/http.go index 8e274bd51179d..cd63708823421 100644 --- a/source/extensions/dynamic_modules/sdk/go/abi/http.go +++ b/source/extensions/dynamic_modules/sdk/go/abi/http.go @@ -1927,7 +1927,7 @@ func envoy_dynamic_module_on_http_filter_new( if factoryWrapper == nil { return nil } - + // Create the plugin wrapper. pluginWrapper := newDymStreamPluginHandle(hostPluginPtr) diff --git a/source/extensions/dynamic_modules/sdk/go/abi/scheduler.go b/source/extensions/dynamic_modules/sdk/go/abi/scheduler.go index 83f66b66bd78d..7ec60f23bbc33 100644 --- a/source/extensions/dynamic_modules/sdk/go/abi/scheduler.go +++ b/source/extensions/dynamic_modules/sdk/go/abi/scheduler.go @@ -20,7 +20,7 @@ type dymScheduler struct { nextTaskID uint64 tasks map[uint64]func() commitFunc func(unsafe.Pointer, C.uint64_t) - deleteFunc func(unsafe.Pointer) + deleteFunc func(unsafe.Pointer) } func newDymScheduler(