Skip to content

Commit

Permalink
golang filter: add GetProperty (envoyproxy#29355)
Browse files Browse the repository at this point in the history
* golang filter: add GetProperty (envoyproxy#28595)

As we already support getting/setting FilterState, we don't need to implement
GetProperty with non-attribute name & SetProperty which actually work on FilterState

* remove assertion which is no longer true

The assertion is no longer true after
envoyproxy@a420821

Solve envoyproxy#28595 (comment)


Signed-off-by: spacewander <[email protected]>
  • Loading branch information
spacewander authored Sep 1, 2023
1 parent 9a2f5fc commit 951d4ba
Show file tree
Hide file tree
Showing 17 changed files with 583 additions and 7 deletions.
6 changes: 6 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,12 @@ updates:
interval: daily
time: "06:00"

- package-ecosystem: "gomod"
directory: "/contrib/golang/filters/http/test/test_data/property"
schedule:
interval: daily
time: "06:00"

- package-ecosystem: "gomod"
directory: "/contrib/golang/router/cluster_specifier/test/test_data/simple"
schedule:
Expand Down
3 changes: 3 additions & 0 deletions contrib/golang/common/go/api/api.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ typedef enum { // NOLINT(modernize-use-using)
CAPIInvalidPhase = -4,
CAPIValueNotFound = -5,
CAPIYield = -6,
CAPIInternalFailure = -7,
CAPISerializationFailure = -8,
} CAPIStatus;

CAPIStatus envoyGoFilterHttpContinue(void* r, int status);
Expand Down Expand Up @@ -82,6 +84,7 @@ void envoyGoConfigHttpFinalize(void* c);
CAPIStatus envoyGoFilterHttpSetStringFilterState(void* r, void* key, void* value, int state_type,
int life_span, int stream_sharing);
CAPIStatus envoyGoFilterHttpGetStringFilterState(void* r, void* key, void* value);
CAPIStatus envoyGoFilterHttpGetStringProperty(void* r, void* key, void* value, int* rc);

CAPIStatus envoyGoFilterHttpDefineMetric(void* c, uint32_t metric_type, void* name,
void* metric_id);
Expand Down
2 changes: 2 additions & 0 deletions contrib/golang/common/go/api/capi.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ type HttpCAPI interface {
HttpSetStringFilterState(r unsafe.Pointer, key string, value string, stateType StateType, lifeSpan LifeSpan, streamSharing StreamSharing)
HttpGetStringFilterState(r unsafe.Pointer, key string) string

HttpGetStringProperty(r unsafe.Pointer, key string) (string, error)

HttpDefineMetric(c unsafe.Pointer, metricType MetricType, name string) uint32
HttpIncrementMetric(c unsafe.Pointer, metricId uint32, offset int64)
HttpGetMetric(c unsafe.Pointer, metricId uint32) uint64
Expand Down
10 changes: 10 additions & 0 deletions contrib/golang/common/go/api/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ type StreamInfo interface {
FilterState() FilterState
// VirtualClusterName returns the name of the virtual cluster which got matched
VirtualClusterName() (string, bool)

// Some fields in stream info can be fetched via GetProperty
// For example, startTime() is equal to GetProperty("request.time")
}

type StreamFilterCallbacks interface {
Expand All @@ -144,6 +147,13 @@ type FilterCallbacks interface {
RecoverPanic()
Log(level LogType, msg string)
LogLevel() LogType
// GetProperty fetch Envoy attribute and return the value as a string.
// The list of attributes can be found in https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/advanced/attributes.
// If the fetch succeeded, a string will be returned.
// If the value is a timestamp, it is returned as a timestamp string like "2023-07-31T07:21:40.695646+00:00".
// If the fetch failed (including the value is not found), an error will be returned.
// Currently, fetching requests/response attributes are mostly unsupported.
GetProperty(key string) (string, error)
// TODO add more for filter callbacks
}

Expand Down
15 changes: 15 additions & 0 deletions contrib/golang/filters/http/source/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,18 @@ envoy_cc_library(
"//source/common/http:headers_lib",
"//source/common/http:utility_lib",
"//source/common/http/http1:codec_lib",
"//source/common/protobuf:utility_lib",
"//source/extensions/filters/common/expr:cel_state_lib",
"//source/extensions/filters/common/expr:evaluator_lib",
"@com_google_cel_cpp//eval/public:activation",
"@com_google_cel_cpp//eval/public:builtin_func_registrar",
"@com_google_cel_cpp//eval/public:cel_expr_builder_factory",
"@com_google_cel_cpp//eval/public:cel_value",
"@com_google_cel_cpp//eval/public:value_export_util",
"@com_google_cel_cpp//eval/public/containers:field_access",
"@com_google_cel_cpp//eval/public/containers:field_backed_list_impl",
"@com_google_cel_cpp//eval/public/containers:field_backed_map_impl",
"@com_google_cel_cpp//eval/public/structs:cel_proto_wrapper",
"@envoy_api//contrib/envoy/extensions/filters/http/golang/v3alpha:pkg_cc_proto",
],
)
Expand Down Expand Up @@ -77,6 +89,9 @@ envoy_cc_library(
"//source/common/http:headers_lib",
"//source/common/http:utility_lib",
"//source/common/http/http1:codec_lib",
"//source/common/protobuf:utility_lib",
"//source/extensions/filters/common/expr:cel_state_lib",
"//source/extensions/filters/common/expr:evaluator_lib",
"@envoy_api//contrib/envoy/extensions/filters/http/golang/v3alpha:pkg_cc_proto",
],
)
9 changes: 9 additions & 0 deletions contrib/golang/filters/http/source/cgo.cc
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,15 @@ CAPIStatus envoyGoFilterHttpGetStringFilterState(void* r, void* key, void* value
});
}

CAPIStatus envoyGoFilterHttpGetStringProperty(void* r, void* key, void* value, int* rc) {
return envoyGoFilterHandlerWrapper(
r, [key, value, rc](std::shared_ptr<Filter>& filter) -> CAPIStatus {
auto key_str = referGoString(key);
auto value_str = reinterpret_cast<GoString*>(value);
return filter->getStringProperty(key_str, value_str, rc);
});
}

CAPIStatus envoyGoFilterHttpDefineMetric(void* c, uint32_t metric_type, void* name,
void* metric_id) {
return envoyGoConfigHandlerWrapper(
Expand Down
56 changes: 49 additions & 7 deletions contrib/golang/filters/http/source/go/pkg/http/capi_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ package http
*/
import "C"
import (
"errors"
"reflect"
"runtime"
"strings"
Expand Down Expand Up @@ -61,21 +62,37 @@ const (

type httpCApiImpl struct{}

// Only CAPIOK is expected, otherwise, it means unexpected stage when invoke C API,
// When the status means unexpected stage when invoke C API,
// panic here and it will be recover in the Go entry function.
func handleCApiStatus(status C.CAPIStatus) {
switch status {
case C.CAPIOK:
return
case C.CAPIFilterIsGone,
C.CAPIFilterIsDestroy,
C.CAPINotInGo,
C.CAPIInvalidPhase:
panic(capiStatusToStr(status))
}
}

func capiStatusToStr(status C.CAPIStatus) string {
switch status {
case C.CAPIFilterIsGone:
panic(errRequestFinished)
return errRequestFinished
case C.CAPIFilterIsDestroy:
panic(errFilterDestroyed)
return errFilterDestroyed
case C.CAPINotInGo:
panic(errNotInGo)
return errNotInGo
case C.CAPIInvalidPhase:
panic(errInvalidPhase)
return errInvalidPhase
case C.CAPIValueNotFound:
return errValueNotFound
case C.CAPIInternalFailure:
return errInternalFailure
case C.CAPISerializationFailure:
return errSerializationFailure
}

return "unknown status"
}

func (c *httpCApiImpl) HttpContinue(r unsafe.Pointer, status uint64) {
Expand Down Expand Up @@ -324,6 +341,31 @@ func (c *httpCApiImpl) HttpGetStringFilterState(rr unsafe.Pointer, key string) s
return strings.Clone(value)
}

func (c *httpCApiImpl) HttpGetStringProperty(rr unsafe.Pointer, key string) (string, error) {
r := (*httpRequest)(rr)
var value string
var rc int
r.mutex.Lock()
defer r.mutex.Unlock()
r.sema.Add(1)
res := C.envoyGoFilterHttpGetStringProperty(unsafe.Pointer(r.req), unsafe.Pointer(&key),
unsafe.Pointer(&value), (*C.int)(unsafe.Pointer(&rc)))
if res == C.CAPIYield {
atomic.AddInt32(&r.waitingOnEnvoy, 1)
r.sema.Wait()
res = C.CAPIStatus(rc)
} else {
r.sema.Done()
handleCApiStatus(res)
}

if res == C.CAPIOK {
return strings.Clone(value), nil
}

return "", errors.New(capiStatusToStr(res))
}

func (c *httpCApiImpl) HttpDefineMetric(cfg unsafe.Pointer, metricType api.MetricType, name string) uint32 {
var value uint32

Expand Down
4 changes: 4 additions & 0 deletions contrib/golang/filters/http/source/go/pkg/http/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ func (r *httpRequest) LogLevel() api.LogType {
return cAPI.HttpLogLevel()
}

func (r *httpRequest) GetProperty(key string) (string, error) {
return cAPI.HttpGetStringProperty(unsafe.Pointer(r), key)
}

func (r *httpRequest) StreamInfo() api.StreamInfo {
return &streamInfo{
request: r,
Expand Down
4 changes: 4 additions & 0 deletions contrib/golang/filters/http/source/go/pkg/http/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ const (
errFilterDestroyed = "golang filter has been destroyed"
errNotInGo = "not proccessing Go"
errInvalidPhase = "invalid phase, maybe headers/buffer already continued"

errInternalFailure = "internal failure"
errValueNotFound = "value not found"
errSerializationFailure = "serialization failure"
)

// api.HeaderMap
Expand Down
Loading

0 comments on commit 951d4ba

Please sign in to comment.