├── .bazelrc ├── .bazelversion ├── .clang-format ├── .clang-tidy ├── .gitignore ├── .gitmodules ├── BUILD.bazel ├── CHANGELOG ├── CONTRIBUTING.md ├── DCO ├── EGo.png ├── LICENSE ├── NOTICE ├── OWNERS.md ├── README.md ├── VERSION ├── WORKSPACE ├── bazel └── get_workspace_status ├── ego-demo.sh ├── ego ├── .gitignore ├── README.md ├── src │ ├── cc │ │ ├── README.md │ │ ├── filter │ │ │ └── http │ │ │ │ ├── BUILD.bazel │ │ │ │ ├── cgo-proxy.cc │ │ │ │ ├── cgo-proxy.h │ │ │ │ ├── factory.cc │ │ │ │ ├── filter-cgo.cc │ │ │ │ ├── filter-goc.cc │ │ │ │ ├── filter-native.cc │ │ │ │ ├── filter.h │ │ │ │ ├── filter.proto │ │ │ │ ├── integration_test.cc │ │ │ │ ├── native.cc │ │ │ │ ├── span-group.cc │ │ │ │ └── span-group.h │ │ └── goc │ │ │ ├── BUILD.bazel │ │ │ ├── bufferinstance.cc │ │ │ ├── envoy.h │ │ │ ├── goc.cc │ │ │ ├── goc.h │ │ │ ├── gohttpfilter.cc │ │ │ ├── log.cc │ │ │ ├── proto │ │ │ ├── BUILD.bazel │ │ │ └── dto.proto │ │ │ ├── requestheadermap.cc │ │ │ ├── requesttrailermap.cc │ │ │ ├── responseheadermap.cc │ │ │ └── stats.cc │ └── go │ │ ├── BUILD.bazel │ │ ├── README.md │ │ ├── envoy │ │ ├── BUILD.bazel │ │ ├── datastatus │ │ │ ├── BUILD.bazel │ │ │ └── const.go │ │ ├── envoy.go │ │ ├── headersstatus │ │ │ ├── BUILD.bazel │ │ │ └── const.go │ │ ├── lifespan │ │ │ ├── BUILD.bazel │ │ │ └── const.go │ │ ├── loglevel │ │ │ ├── BUILD.bazel │ │ │ └── const.go │ │ ├── statetype │ │ │ ├── BUILD.bazel │ │ │ └── const.go │ │ ├── stats │ │ │ ├── BUILD.bazel │ │ │ └── const.go │ │ └── trailersstatus │ │ │ ├── BUILD.bazel │ │ │ └── const.go │ │ ├── httpfilter.go │ │ ├── internal │ │ └── cgo │ │ │ ├── BUILD.bazel │ │ │ ├── bufferinstance.go │ │ │ ├── clutch.go │ │ │ ├── clutch_test.go │ │ │ ├── cutils.go │ │ │ ├── decoder_callbacks.go │ │ │ ├── encoder_callbacks.go │ │ │ ├── filter_state.go │ │ │ ├── gohttpfilter.go │ │ │ ├── gohttpfilterconfig.go │ │ │ ├── logger.go │ │ │ ├── main.go │ │ │ ├── requestheadermap.go │ │ │ ├── requesttrailermap.go │ │ │ ├── responseheadermap.go │ │ │ ├── route.go │ │ │ ├── span.go │ │ │ ├── stats.go │ │ │ └── stream_info.go │ │ ├── logger │ │ ├── BUILD.bazel │ │ └── logger.go │ │ ├── registry.go │ │ └── volatile │ │ ├── BUILD.bazel │ │ └── volatile.go └── test │ ├── cc │ ├── filter │ │ └── http │ │ │ ├── BUILD.bazel │ │ │ ├── filter_test.cc │ │ │ ├── linkopts.bzl │ │ │ ├── mocks.h │ │ │ └── span-group_test.cc │ └── goc │ │ ├── BUILD.bazel │ │ └── requestheadermap_test.cc │ └── go │ └── mock │ ├── BUILD.bazel │ ├── doc.go │ ├── envoy.go │ ├── gen │ └── envoy │ │ ├── BUILD.bazel │ │ ├── buffer_instance.go │ │ ├── counter.go │ │ ├── decoder_filter_callbacks.go │ │ ├── encoder_filter_callbacks.go │ │ ├── filter_state.go │ │ ├── gauge.go │ │ ├── generic_secret_config_provider.go │ │ ├── go_http_filter.go │ │ ├── go_http_filter_config.go │ │ ├── header_map.go │ │ ├── header_map_read_only.go │ │ ├── header_map_updatable.go │ │ ├── histogram.go │ │ ├── path_match_criterion.go │ │ ├── request_header_map.go │ │ ├── request_header_map_read_only.go │ │ ├── request_header_map_updatable.go │ │ ├── request_or_response_header_map.go │ │ ├── request_or_response_header_map_read_only.go │ │ ├── request_or_response_header_map_updatable.go │ │ ├── request_trailer_map.go │ │ ├── request_trailer_map_read_only.go │ │ ├── request_trailer_map_updatable.go │ │ ├── response_header_map.go │ │ ├── response_header_map_read_only.go │ │ ├── response_header_map_updatable.go │ │ ├── route.go │ │ ├── route_entry.go │ │ ├── scope.go │ │ ├── span.go │ │ ├── stream_filter_callbacks.go │ │ └── stream_info.go │ └── logger.go ├── egofilters ├── BUILD.bazel ├── filters.go ├── http │ ├── getheader │ │ ├── BUILD.bazel │ │ ├── factory.go │ │ ├── filter.go │ │ └── proto │ │ │ ├── BUILD.bazel │ │ │ └── getheader.proto │ └── security │ │ ├── BUILD.bazel │ │ ├── config.go │ │ ├── config_test.go │ │ ├── context │ │ ├── BUILD.bazel │ │ ├── context.go │ │ ├── request_context.go │ │ ├── request_context_test.go │ │ ├── response_context.go │ │ └── response_context_test.go │ │ ├── factory.go │ │ ├── factory_test.go │ │ ├── filter.go │ │ ├── filter_sign_test.go │ │ ├── filter_verify_test.go │ │ ├── http │ │ ├── BUILD.bazel │ │ ├── http_client.go │ │ └── http_client_test.go │ │ ├── proto │ │ ├── BUILD.bazel │ │ └── security.proto │ │ └── verifier │ │ ├── BUILD.bazel │ │ ├── base_provider.go │ │ ├── consts.go │ │ ├── custom_hmac_provider.go │ │ ├── custom_hmac_provider_factory_test.go │ │ ├── custom_hmac_provider_sign_required_test.go │ │ ├── custom_hmac_provider_sign_test.go │ │ ├── custom_hmac_provider_verify_test.go │ │ ├── custom_hmac_validator.go │ │ ├── custom_hmac_validator_test.go │ │ └── verifier.go └── mock │ ├── BUILD.bazel │ ├── doc.go │ └── gen │ └── http │ └── security │ ├── context │ ├── BUILD.bazel │ ├── callbacks.go │ ├── context.go │ ├── request_context.go │ ├── response_callbacks.go │ └── response_context.go │ ├── http │ ├── BUILD.bazel │ ├── http_client.go │ └── http_client_with_ctx.go │ ├── proto │ ├── BUILD.bazel │ ├── is_provider__provider_type.go │ └── is_requirement__requires_type.go │ └── verifier │ ├── BUILD.bazel │ ├── get_current_time_opt.go │ ├── is_valid_hmac_signature_opt.go │ ├── signer.go │ └── verifier.go ├── envoy.yaml ├── external └── gomockery.patch ├── go.mod ├── go.sum ├── services ├── echo │ ├── BUILD.bazel │ └── main.go └── hmac │ ├── BUILD.bazel │ └── main.go └── tools ├── copy_pb_go.py ├── gen_compilation_database.py ├── generate_test_coverage_report.sh └── sync.sh /.bazelrc: -------------------------------------------------------------------------------- 1 | import %workspace%/envoy/.bazelrc 2 | -------------------------------------------------------------------------------- /.bazelversion: -------------------------------------------------------------------------------- 1 | envoy/.bazelversion -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | envoy/.clang-format -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | envoy/.clang-tidy -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bazel-* 2 | BROWSE 3 | /build 4 | /build_* 5 | *.bzlc 6 | .cache 7 | .clangd 8 | .classpath 9 | .clwb/ 10 | /ci/bazel-* 11 | compile_commands.json 12 | cscope.* 13 | .deps 14 | .devcontainer.json 15 | /docs/landing_source/.bundle 16 | /generated 17 | .history/ 18 | .idea/ 19 | .project 20 | *.pyc 21 | **/pyformat 22 | SOURCE_VERSION 23 | .settings/ 24 | *.sw* 25 | tags 26 | TAGS 27 | /test/coverage/BUILD 28 | /tools/spelling/.aspell.en.pws 29 | .vimrc 30 | .vs 31 | .vscode 32 | clang-tidy-fixes.yaml 33 | clang.bazelrc 34 | user.bazelrc 35 | CMakeLists.txt 36 | cmake-build-debug 37 | *.pb.go 38 | *.pb.validate.go 39 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "envoy"] 2 | path = envoy 3 | url = https://github.com/envoyproxy/envoy 4 | -------------------------------------------------------------------------------- /BUILD.bazel: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | load( 4 | "@envoy//bazel:envoy_build_system.bzl", 5 | "envoy_cc_binary", 6 | "envoy_cc_library", 7 | "envoy_cc_test", 8 | ) 9 | 10 | envoy_cc_binary( 11 | name = "envoy", 12 | repository = "@envoy", 13 | linkopts = select({ 14 | "@bazel_tools//src/conditions:darwin": ["-framework Security"], 15 | "//conditions:default": [], 16 | }), 17 | deps = [ 18 | "//egofilters:ego_filter_protos", 19 | "//ego/src/cc/filter/http:factory", 20 | "//ego/src/cc/goc:goc", 21 | "@envoy//source/exe:envoy_main_entry_lib", 22 | ], 23 | ) 24 | 25 | sh_test( 26 | name = "ego-demo", 27 | srcs = [ 28 | "ego-demo.sh", 29 | ], 30 | data = [ 31 | "//:envoy.yaml", 32 | "//:envoy", 33 | "//services/echo:echo", 34 | "//services/hmac:hmac", 35 | ], 36 | ) 37 | 38 | load("@bazel_gazelle//:def.bzl", "gazelle") 39 | 40 | # Exclude vscode history plugin folder ;-) 41 | # gazelle:exclude .history 42 | # gazelle:exclude envoy 43 | # gazelle:exclude tools 44 | 45 | # gazelle:prefix github.com/grab/ego 46 | 47 | # run gazelle to udate bazel build files 48 | gazelle(name = "gazelle") 49 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | 2 | v0.0.1 3 | ====== 4 | 5 | This is the initial public release. It works with Envoy 1.14.6 and supports 6 | Go-routines and zero-copy interactions. -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Communication 2 | 3 | Before making a proposal, please spend some time investigating / prototyping. 4 | The devil is in the details, and the feedback from Bazel, linker, and compilers 5 | has proven more convincing than our feeble human voices. 6 | 7 | If you find a bug, please create an issue, and if you want to pick up a larger 8 | chunk of work (like exposing a new C++ interface in Go), please do the same for 9 | better visibility. 10 | 11 | # Coding style 12 | 13 | In the absence of documents, please do stick to the style you find in existing 14 | code. For Go, this is rather canonical, for C/C++, we have added .clang-format 15 | and .clang-tidy configurations to avoid major accidents. 16 | 17 | Besides that, please keep in mind that this is not a golf course. Simple, and 18 | possibly repetitive code is favoured over ingenious meta tricks that do little 19 | more than make maintainance and debugging more difficult. 20 | 21 | # DCO: Sign your work 22 | 23 | Please do sign your work certifying that you have the right to pass it on as an 24 | open-source patch. The rules are pretty simple: if you can certify the contents 25 | of the [DCO](DCO) document contained in this repository, then you just add a 26 | line to every git commit message: 27 | 28 | Signed-off-by: Joe Smith 29 | 30 | using your _real name_. You can also add the sign off via `git commit -s`. Note 31 | that _every_ commit needs to have proper sign-off. 32 | -------------------------------------------------------------------------------- /DCO: -------------------------------------------------------------------------------- 1 | Developer Certificate of Origin 2 | Version 1.1 3 | 4 | Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 5 | 1 Letterman Drive 6 | Suite D4700 7 | San Francisco, CA, 94129 8 | 9 | Everyone is permitted to copy and distribute verbatim copies of this 10 | license document, but changing it is not allowed. 11 | 12 | 13 | Developer's Certificate of Origin 1.1 14 | 15 | By making a contribution to this project, I certify that: 16 | 17 | (a) The contribution was created in whole or in part by me and I 18 | have the right to submit it under the open source license 19 | indicated in the file; or 20 | 21 | (b) The contribution is based upon previous work that, to the best 22 | of my knowledge, is covered under an appropriate open source 23 | license and I have the right under that license to submit that 24 | work with modifications, whether created in whole or in part 25 | by me, under the same open source license (unless I am 26 | permitted to submit under a different license), as indicated 27 | in the file; or 28 | 29 | (c) The contribution was provided directly to me by some other 30 | person who certified (a), (b) or (c) and I have not modified 31 | it. 32 | 33 | (d) I understand and agree that this project and the contribution 34 | are public and that a record of the contribution (including all 35 | personal information I submit with it, including my sign-off) is 36 | maintained indefinitely and may be redistributed consistent with 37 | this project or the open source license(s) involved. 38 | -------------------------------------------------------------------------------- /EGo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myteksi/ego-demo/063d18e147b619d415880e6be6765c6652531c90/EGo.png -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | EGo -- Writing Envoy filters in Go 2 | 3 | Copyright 2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 4 | 5 | Use of this source code is governed by the Apache License 2.0 that can be found in the LICENSE file -------------------------------------------------------------------------------- /OWNERS.md: -------------------------------------------------------------------------------- 1 | Maintainers 2 | 3 | * Bjorn Karge ([bkgs](https://github.com/bkgs)) (bjorn.karge@grab.com) 4 | * Tien Nguyen Van ([tiennv147](https://github.com/tiennv147)) (tien.nguyenvan@grab.com) 5 | * Xuan Nguyen Duc ([xuanit](https://github.com/xuanit)) (xuan.nguyen@grab.com) 6 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.0.70 2 | -------------------------------------------------------------------------------- /bazel/get_workspace_status: -------------------------------------------------------------------------------- 1 | ../envoy/bazel/get_workspace_status -------------------------------------------------------------------------------- /ego-demo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | 4 | set -e 5 | 6 | services/echo/echo & services/hmac/hmac & envoy -c envoy.yaml -------------------------------------------------------------------------------- /ego/.gitignore: -------------------------------------------------------------------------------- 1 | /bazel-* 2 | BROWSE 3 | /build 4 | /build_* 5 | *.bzlc 6 | .cache 7 | .clangd 8 | .classpath 9 | .clwb/ 10 | /ci/bazel-* 11 | compile_commands.json 12 | cscope.* 13 | .deps 14 | .devcontainer.json 15 | /docs/landing_source/.bundle 16 | /generated 17 | .history/ 18 | .idea/ 19 | .project 20 | *.pyc 21 | **/pyformat 22 | SOURCE_VERSION 23 | .settings/ 24 | *.sw* 25 | tags 26 | TAGS 27 | /test/coverage/BUILD 28 | /tools/spelling/.aspell.en.pws 29 | .vimrc 30 | .vs 31 | .vscode 32 | clang-tidy-fixes.yaml 33 | clang.bazelrc 34 | user.bazelrc 35 | CMakeLists.txt 36 | cmake-build-debug 37 | -------------------------------------------------------------------------------- /ego/README.md: -------------------------------------------------------------------------------- 1 | This repository contains a shim for simplifying development of envoy filters using Golang. 2 | 3 | Due to poorly understood build mechanics, this presently isn't a Bazel workspace in its own right. 4 | 5 | Rather, it needs to be added as git submodule into a repository that also embeds envoy and provides the actual filter implementations. 6 | 7 | In fact, this repository even has a reference to a directory in the embedding project (egofilters), see `src/go/internal/cgo/cutils.go`. 8 | 9 | The reason for this is that the filters in the embedding project need to register themselves via package init() calls that would never be run as part of the cgo static library initialization, otherwise. 10 | 11 | This is aggravated by the fact that Bazel's `rules_go` presently only allows one Cgo package. -------------------------------------------------------------------------------- /ego/src/cc/README.md: -------------------------------------------------------------------------------- 1 | # Envoy Golang Filter Demo 2 | 3 | This project demonstrates the linking of additional HTTP filters implemented in Go with the Envoy binary. 4 | 5 | A new filter `add-header` which adds a HTTP header is introduced. 6 | 7 | Integration tests demonstrating the filter's end-to-end behavior are 8 | also provided. 9 | 10 | ## Building 11 | 12 | To build the Envoy static binary: 13 | 14 | 1. `git submodule update --init` 15 | 2. `bazel build //:envoy` 16 | 17 | ## Testing 18 | 19 | To run the `add-header` integration test: 20 | 21 | `bazel test //src/cc/filter/http/addheader:integration_test` 22 | 23 | # Layout / Packages 24 | 25 | # cgo 26 | 27 | This package provides two libraries: one for supporting upcalls to Go (`cgo`) and one for supporting downcalls from Go (`native`). 28 | 29 | In order to avoid circular dependencies, the `cgo` library must not be used as dependency for the Golang packages. Rather, these need to depend on the `native` package only. 30 | 31 | Both libraries use the file `envoy.h`: one indirectly (via Go code) and one directly (included by the downcall proxies). 32 | 33 | # filter -------------------------------------------------------------------------------- /ego/src/cc/filter/http/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_go//go:def.bzl", "go_library") 2 | load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") 3 | 4 | # gazelle:ignore 5 | 6 | # Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 7 | # 8 | # Use of this source code is governed by the Apache License 2.0 that can be 9 | # found in the LICENSE file 10 | 11 | package(default_visibility = ["//visibility:public"]) 12 | 13 | load( 14 | "@envoy//bazel:envoy_build_system.bzl", 15 | "envoy_cc_binary", 16 | "envoy_cc_library", 17 | "envoy_cc_test", 18 | ) 19 | load( 20 | "@envoy_api//bazel:api_build_system.bzl", 21 | "api_proto_package", 22 | ) 23 | load( 24 | "@envoy//test/extensions:extensions_build_system.bzl", 25 | "envoy_extension_cc_test", 26 | ) 27 | 28 | api_proto_package( 29 | deps = [ 30 | "@envoy_api//envoy/extensions/transport_sockets/tls/v3:pkg", 31 | ], 32 | ) 33 | 34 | # :native contains code that does not (directly or indirectly) interact with Go 35 | # This library is referenced by the Go code (so that we avoid circular deps) 36 | envoy_cc_library( 37 | name = "native", 38 | srcs = [ 39 | "filter-native.cc", 40 | "native.cc", 41 | "span-group.cc", 42 | ], 43 | hdrs = [ 44 | "filter.h", 45 | "cgo-proxy.h", 46 | "span-group.h", 47 | ], 48 | repository = "@envoy", 49 | deps = [ 50 | ":pkg_cc_proto", 51 | "@envoy//source/exe:envoy_common_lib", 52 | ], 53 | ) 54 | 55 | # :cgo contains code that directly or indirectly interacts with Go, or code 56 | # that is only needed by such code. Don't reference this from the Go packages 57 | # as this may create circular dependencies. 58 | envoy_cc_library( 59 | name = "cgo", 60 | srcs = [ 61 | "filter-cgo.cc", 62 | "cgo-proxy.cc", 63 | ], 64 | repository = "@envoy", 65 | deps = [ 66 | ":native", 67 | "//ego/src/go/internal/cgo:cgo.cc", 68 | "//ego/src/cc/goc:goc", 69 | ], 70 | ) 71 | 72 | # :goc contains code that is called from Go ("downcalls"). We need to separate 73 | # this from the code that calls Go ("upcalls") in order to avoid circular deps. 74 | # There is one circle here which is created by a downcall that needs to trigger 75 | # an upcall. This has been decoupled for the compiler by wrapping the upcall in 76 | # a virtual function. 77 | envoy_cc_library( 78 | name = "goc", 79 | srcs = [ 80 | "filter-goc.cc", 81 | ], 82 | hdrs = [ 83 | "filter.h", 84 | ], 85 | repository = "@envoy", 86 | deps = [ 87 | ":native", 88 | # ":cgo", we're not declaring post->onPost dependency, but that's fine. 89 | ":pkg_cc_proto", 90 | "@envoy//source/exe:envoy_common_lib", 91 | ], 92 | ) 93 | 94 | # :factory contains everything needed by the filter factory. Typically pulled 95 | # in by top-level packages 96 | envoy_cc_library( 97 | name = "factory", 98 | srcs = ["factory.cc"], 99 | repository = "@envoy", 100 | deps = [ 101 | ":cgo", 102 | ":native", 103 | "@envoy//include/envoy/server:filter_config_interface", 104 | ], 105 | ) 106 | 107 | # :integration_test can be used to conveniently run the integration tests: 108 | # `bazel test //src/cc/filter/http/getheader:integration_test` 109 | # envoy_cc_test( 110 | # name = "integration_test", 111 | # srcs = ["integration_test.cc"], 112 | # repository = "@envoy", 113 | # deps = [ 114 | # ":factory", 115 | # ":native", 116 | # "@envoy//test/integration:http_integration_lib", 117 | # ], 118 | # ) 119 | -------------------------------------------------------------------------------- /ego/src/cc/filter/http/cgo-proxy.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | #include "cgo-proxy.h" 7 | 8 | #include "ego/src/cc/goc/goc.h" 9 | #include "ego/src/go/internal/cgo/cgo.h" 10 | 11 | namespace Envoy { 12 | namespace Http { 13 | 14 | CgoProxyImpl::CgoProxyImpl() = default; 15 | 16 | CgoProxyImpl::~CgoProxyImpl() = default; 17 | 18 | unsigned long long CgoProxyImpl::GoHttpFilterCreate(void* native, unsigned long long factory_tag, 19 | unsigned long long filter_slot) { 20 | return Cgo_GoHttpFilter_Create(native, factory_tag, filter_slot); 21 | } 22 | 23 | void CgoProxyImpl::GoHttpFilterOnDestroy(unsigned long long filter_tag) { 24 | Cgo_GoHttpFilter_OnDestroy(filter_tag); 25 | } 26 | 27 | long long CgoProxyImpl::GoHttpFilterDecodeHeaders(unsigned long long filter_tag, void* headers, 28 | int end_stream) { 29 | return Cgo_GoHttpFilter_DecodeHeaders(filter_tag, headers, end_stream); 30 | } 31 | 32 | long long CgoProxyImpl::GoHttpFilterDecodeData(unsigned long long filter_tag, void* buffer, 33 | int end_stream) { 34 | return Cgo_GoHttpFilter_DecodeData(filter_tag, buffer, end_stream); 35 | } 36 | 37 | long long CgoProxyImpl::GoHttpFilterDecodeTrailers(unsigned long long filter_tag, void* trailers) { 38 | return Cgo_GoHttpFilter_DecodeTrailers(filter_tag, trailers); 39 | } 40 | 41 | long long CgoProxyImpl::GoHttpFilterEncodeHeaders(unsigned long long filter_tag, void* headers, 42 | int end_stream) { 43 | return Cgo_GoHttpFilter_EncodeHeaders(filter_tag, headers, end_stream); 44 | } 45 | 46 | long long CgoProxyImpl::GoHttpFilterEncodeData(unsigned long long filter_tag, void* buffer, 47 | int end_stream) { 48 | return Cgo_GoHttpFilter_EncodeData(filter_tag, buffer, end_stream); 49 | } 50 | 51 | void CgoProxyImpl::GoHttpFilterOnPost(unsigned long long filter_tag, unsigned long long post_tag) { 52 | return Cgo_GoHttpFilter_OnPost(filter_tag, post_tag); 53 | } 54 | } // namespace Http 55 | } // namespace Envoy -------------------------------------------------------------------------------- /ego/src/cc/filter/http/cgo-proxy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 3 | // 4 | // Use of this source code is governed by the Apache License 2.0 that can be 5 | // found in the LICENSE file 6 | 7 | #include 8 | 9 | namespace Envoy { 10 | namespace Http { 11 | 12 | class CgoProxy { 13 | public: 14 | virtual ~CgoProxy(); 15 | 16 | virtual unsigned long long GoHttpFilterCreate(void* native, unsigned long long factory_tag, 17 | unsigned long long filter_slot) = 0; 18 | virtual void GoHttpFilterOnDestroy(unsigned long long filter_tag) = 0; 19 | virtual long long GoHttpFilterDecodeHeaders(unsigned long long filter_tag, void* headers, 20 | int end_stream) = 0; 21 | virtual long long GoHttpFilterDecodeData(unsigned long long filter_tag, void* buffer, 22 | int end_stream) = 0; 23 | virtual long long GoHttpFilterDecodeTrailers(unsigned long long filter_tag, void* trailers) = 0; 24 | virtual long long GoHttpFilterEncodeHeaders(unsigned long long filter_tag, void* headers, 25 | int end_stream) = 0; 26 | virtual long long GoHttpFilterEncodeData(unsigned long long filter_tag, void* headers, 27 | int end_stream) = 0; 28 | virtual void GoHttpFilterOnPost(unsigned long long filter_tag, unsigned long long post_tag) = 0; 29 | }; 30 | 31 | class CgoProxyImpl : public CgoProxy { 32 | public: 33 | CgoProxyImpl(); 34 | ~CgoProxyImpl() override; 35 | 36 | unsigned long long GoHttpFilterCreate(void* native, unsigned long long factory_tag, 37 | unsigned long long filter_slot) override; 38 | void GoHttpFilterOnDestroy(unsigned long long filter_tag) override; 39 | long long GoHttpFilterDecodeHeaders(unsigned long long filter_tag, void* headers, 40 | int end_stream) override; 41 | long long GoHttpFilterDecodeData(unsigned long long filter_tag, void* buffer, 42 | int end_stream) override; 43 | long long GoHttpFilterDecodeTrailers(unsigned long long filter_tag, void* trailers) override; 44 | long long GoHttpFilterEncodeHeaders(unsigned long long filter_tag, void* headers, 45 | int end_stream) override; 46 | long long GoHttpFilterEncodeData(unsigned long long filter_tag, void* headers, 47 | int end_stream) override; 48 | void GoHttpFilterOnPost(unsigned long long filter_tag, unsigned long long post_tag) override; 49 | }; 50 | 51 | using CgoProxyPtr = std::shared_ptr; 52 | } // namespace Http 53 | } // namespace Envoy -------------------------------------------------------------------------------- /ego/src/cc/filter/http/filter-native.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | #include "common/common/empty_string.h" 7 | 8 | #include "filter.h" 9 | 10 | namespace Envoy { 11 | namespace Http { 12 | 13 | void GoHttpFilter::setDecoderFilterCallbacks(StreamDecoderFilterCallbacks& callbacks) { 14 | ASSERT(0 < pins_.load()); 15 | ASSERT(0 == decoderCallbacks_); 16 | // Assuming dispatcher is shared between callbacks 17 | // https://github.com/envoyproxy/envoy/blob/master/include/envoy/thread_local/thread_local.h 18 | ASSERT(nullptr == dispatcher_); 19 | 20 | decoderCallbacks_ = &callbacks; 21 | dispatcher_ = &callbacks.dispatcher(); 22 | 23 | // Handle logic can not create fitler on Go-side 24 | if (cgoTag_ == 0) { 25 | decoderCallbacks_->sendLocalReply(Code::InternalServerError, EMPTY_STRING, nullptr, 26 | absl::nullopt, EMPTY_STRING); 27 | } 28 | } 29 | 30 | void GoHttpFilter::setEncoderFilterCallbacks(StreamEncoderFilterCallbacks& callbacks) { 31 | ASSERT(0 < pins_.load()); 32 | ASSERT(0 == encoderCallbacks_); 33 | 34 | encoderCallbacks_ = &callbacks; 35 | } 36 | 37 | uint64_t GoHttpRouteSpecificFilterConfig::cgoTag(std::string filterName) const { 38 | auto it = filters_.find(filterName); 39 | if (it != filters_.cend()) { 40 | return it->second; 41 | } 42 | return 0; 43 | } 44 | 45 | GoHttpRouteSpecificFilterConfig::~GoHttpRouteSpecificFilterConfig() { onDestroy_(); } 46 | 47 | } // namespace Http 48 | } // namespace Envoy -------------------------------------------------------------------------------- /ego/src/cc/filter/http/filter.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | syntax = "proto3"; 7 | 8 | package ego.http; 9 | 10 | import "validate/validate.proto"; 11 | import "google/protobuf/any.proto"; 12 | import "envoy/extensions/transport_sockets/tls/v3/cert.proto"; 13 | 14 | message Settings { 15 | 16 | // The filter name used with ego.RegisterHttpFilter 17 | string filter = 1 [(validate.rules).string.min_bytes = 1]; 18 | 19 | // For bools, the default value is false. so if it available it should be true 20 | // And it will be generated with crash_on_errors = true in envoy.yaml for 21 | // testing, canary deploy to let Envoy crash by throwing an exception 22 | bool crash_on_errors = 2; 23 | 24 | // An Any that must match the structure expected by the respective filter. 25 | // usually annotated with a @type attribute to avoid accidents. 26 | google.protobuf.Any settings = 3; 27 | 28 | // We support access to SDS via the envoy runtime, so here is where the 29 | // coordinates for the secrets needed by the filter can be configured. See 30 | // https://github.com/envoyproxy/envoy/blob/v1.14.1/api/envoy/api/v2/auth/cert.proto 31 | // (message SdsSecretConfig) for more information. 32 | // 33 | // Example 1: remote SDS 34 | // --- 35 | // sds_config: 36 | // api_config_source: 37 | // api_type: GRPC 38 | // grpc_services: 39 | // envoy_grpc: 40 | // cluster_name: sds_server_uds 41 | // 42 | // Example 2: static file; this can not be configured via dynamic resources 43 | // --- 44 | // sds_config: 45 | // path: ./test/secret-resource.yaml 46 | // 47 | // Example 3: static resources, leave sds_config empty 48 | // --- 49 | // static_resources: 50 | // secrets: 51 | // - name: "/ego-demo/v1/secret" 52 | // generic_secret: 53 | // secret: 54 | // inline_string: 55 | // 56 | envoy.extensions.transport_sockets.tls.v3.SdsSecretConfig sds_secret_config = 4; 57 | } 58 | 59 | message SettingsPerRoute { 60 | map filters = 1; 61 | } -------------------------------------------------------------------------------- /ego/src/cc/filter/http/integration_test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | #include "test/integration/http_integration.h" 7 | 8 | namespace Envoy { 9 | class HttpFilterSampleIntegrationTest : public HttpIntegrationTest, 10 | public testing::TestWithParam { 11 | public: 12 | HttpFilterSampleIntegrationTest() 13 | : HttpIntegrationTest(Http::CodecClient::Type::HTTP1, GetParam(), realTime()) {} 14 | /** 15 | * Initializer for an individual integration test. 16 | */ 17 | void SetUp() override { initialize(); } 18 | 19 | void initialize() override { 20 | config_helper_.addFilter("{ name: get-header, config: { key: add-header-key, src: " 21 | "'https://google.com', hdr: add-header-value } }"); 22 | HttpIntegrationTest::initialize(); 23 | } 24 | }; 25 | 26 | INSTANTIATE_TEST_SUITE_P(IpVersions, HttpFilterSampleIntegrationTest, 27 | testing::ValuesIn(TestEnvironment::getIpVersionsForTest())); 28 | 29 | TEST_P(HttpFilterSampleIntegrationTest, Test1) { 30 | Http::TestRequestHeaderMapImpl headers{ 31 | {":method", "GET"}, {":path", "/"}, {":authority", "host"}}; 32 | 33 | IntegrationCodecClientPtr codec_client; 34 | FakeHttpConnectionPtr fake_upstream_connection; 35 | FakeStreamPtr request_stream; 36 | 37 | codec_client = makeHttpConnection(lookupPort("http")); 38 | auto response = codec_client->makeHeaderOnlyRequest(headers); 39 | ASSERT_TRUE(fake_upstreams_[0]->waitForHttpConnection(*dispatcher_, fake_upstream_connection)); 40 | ASSERT_TRUE(fake_upstream_connection->waitForNewStream(*dispatcher_, request_stream)); 41 | ASSERT_TRUE(request_stream->waitForEndStream(*dispatcher_)); 42 | response->waitForEndStream(); 43 | 44 | EXPECT_EQ("add-header-value", request_stream->headers() 45 | .get(Http::LowerCaseString("add-header-key")) 46 | ->value() 47 | .getStringView()); 48 | 49 | codec_client->close(); 50 | } 51 | } // namespace Envoy 52 | -------------------------------------------------------------------------------- /ego/src/cc/filter/http/native.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | #include "cgo-proxy.h" 7 | 8 | namespace Envoy { 9 | namespace Http { 10 | CgoProxy::~CgoProxy() = default; 11 | } 12 | } // namespace Envoy -------------------------------------------------------------------------------- /ego/src/cc/filter/http/span-group.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | #include "span-group.h" 7 | #include "common/tracing/http_tracer_impl.h" 8 | 9 | namespace Envoy { 10 | namespace Http { 11 | 12 | SpanGroup::SpanGroup():decoderCallbacks_(nullptr),encoderCallbacks_(nullptr){} 13 | 14 | intptr_t SpanGroup::spawnChildSpan(const intptr_t parent_span_id, std::string &name) { 15 | auto span = getSpan(parent_span_id).spawnChild(Envoy::Tracing::EgressConfig::get(), name, decoderCallbacks_->dispatcher().timeSource().systemTime()); 16 | auto id = reinterpret_cast(span.get()); 17 | setSpan(id, std::move(span)); 18 | return id; 19 | } 20 | 21 | void SpanGroup::setSpan(const intptr_t id, Envoy::Tracing::SpanPtr span){ 22 | std::lock_guard guard(spans_mutex); 23 | spans_[id] = std::move(span); 24 | } 25 | 26 | Envoy::Tracing::Span& SpanGroup::getSpan_(const intptr_t span_id){ 27 | std::lock_guard guard(spans_mutex); 28 | auto search = spans_.find(span_id); 29 | 30 | if (search != spans_.end()) { 31 | return *search->second; 32 | } 33 | 34 | return Envoy::Tracing::NullSpan::instance(); 35 | } 36 | 37 | void SpanGroup::removeSpan(const intptr_t span_id){ 38 | std::lock_guard guard(spans_mutex); 39 | spans_.erase(span_id); 40 | } 41 | 42 | Envoy::Tracing::Span& SpanGroup::getSpan(const intptr_t span_id) { 43 | if (SpanGroupConstants::get().DecoderActiveSpan == span_id) { 44 | if (nullptr == decoderCallbacks_) { 45 | return Envoy::Tracing::NullSpan::instance(); 46 | } 47 | return decoderCallbacks_->activeSpan(); 48 | } 49 | 50 | if (SpanGroupConstants::get().EncoderActiveSpan == span_id) { 51 | if (nullptr == encoderCallbacks_) { 52 | return Envoy::Tracing::NullSpan::instance(); 53 | } 54 | return encoderCallbacks_->activeSpan(); 55 | } 56 | 57 | return getSpan_(span_id); 58 | } 59 | 60 | void SpanGroup::setDecoderFilterCallbacks(StreamDecoderFilterCallbacks& callbacks) { 61 | decoderCallbacks_ = &callbacks; 62 | } 63 | 64 | void SpanGroup::setEncoderFilterCallbacks(StreamEncoderFilterCallbacks& callbacks) { 65 | encoderCallbacks_ = &callbacks; 66 | } 67 | 68 | } 69 | } -------------------------------------------------------------------------------- /ego/src/cc/filter/http/span-group.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 3 | // 4 | // Use of this source code is governed by the Apache License 2.0 that can be 5 | // found in the LICENSE file 6 | 7 | #include 8 | #include "envoy/server/filter_config.h" 9 | 10 | namespace Envoy { 11 | namespace Http { 12 | 13 | struct SpanGroupConstantValues { 14 | const int EncoderActiveSpan = 0; 15 | const int DecoderActiveSpan = -1; 16 | }; 17 | 18 | using SpanGroupConstants = ConstSingleton; 19 | 20 | class SpanGroup { 21 | public: 22 | SpanGroup(); 23 | intptr_t spawnChildSpan(const intptr_t parent_span_id, std::string &name); 24 | Envoy::Tracing::Span& getSpan(const intptr_t span_id); 25 | void removeSpan(const intptr_t span_id); 26 | void setDecoderFilterCallbacks(StreamDecoderFilterCallbacks& callbacks); 27 | void setEncoderFilterCallbacks(StreamEncoderFilterCallbacks& callbacks); 28 | 29 | private: 30 | void setSpan(const intptr_t id, Envoy::Tracing::SpanPtr span); 31 | Envoy::Tracing::Span& getSpan_(const intptr_t span_id); 32 | 33 | std::map> spans_; 34 | std::mutex spans_mutex; 35 | // Do only access from dispatcher context. Do check if non-0 before use. 36 | StreamDecoderFilterCallbacks* decoderCallbacks_; 37 | StreamEncoderFilterCallbacks* encoderCallbacks_; 38 | }; 39 | 40 | using SpanGroupPtr = std::unique_ptr; 41 | 42 | } 43 | } -------------------------------------------------------------------------------- /ego/src/cc/goc/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | # 3 | # Use of this source code is governed by the Apache License 2.0 that can be 4 | # found in the LICENSE file 5 | 6 | package(default_visibility = ["//visibility:public"]) 7 | 8 | load( 9 | "@envoy//bazel:envoy_build_system.bzl", 10 | "envoy_cc_library", 11 | "envoy_cc_test", 12 | ) 13 | 14 | # :goc contains code that is called from Go ("downcalls"). We need to separate 15 | # this from the code that calls Go ("upcalls") in order to avoid circular deps. 16 | # 17 | envoy_cc_library( 18 | name = "goc", 19 | srcs = [ 20 | "bufferinstance.cc", 21 | "goc.cc", 22 | "gohttpfilter.cc", 23 | "log.cc", 24 | "requestheadermap.cc", 25 | "responseheadermap.cc", 26 | "requesttrailermap.cc", 27 | "stats.cc", 28 | ], 29 | hdrs = [ 30 | "goc.h", 31 | "envoy.h", 32 | ], 33 | repository = "@envoy", 34 | deps = [ 35 | "//ego/src/cc/filter/http:goc", 36 | "//ego/src/cc/goc/proto:pkg_cc_proto", 37 | "@envoy//include/envoy/http:filter_interface", 38 | "@envoy//source/common/router:string_accessor_lib", 39 | ], 40 | ) 41 | -------------------------------------------------------------------------------- /ego/src/cc/goc/bufferinstance.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | #include 7 | 8 | #include "envoy/buffer/buffer.h" 9 | 10 | #include "envoy.h" 11 | 12 | // BufferInstance 13 | uint64_t BufferInstance_copyOut(void* bufferInstance, size_t start, GoBuf buf) { 14 | auto that = static_cast(bufferInstance); 15 | if (that->length() <= start) 16 | return 0; 17 | 18 | auto size = that->length() - start; 19 | if (buf.len < size) 20 | size = buf.len; 21 | 22 | that->copyOut(start, size, buf.data); 23 | return size; 24 | } 25 | 26 | uint64_t BufferInstance_length(void* bufferInstance) { 27 | auto that = static_cast(bufferInstance); 28 | return that->length(); 29 | } 30 | 31 | uint64_t BufferInstance_getRawSlicesCount(void* bufferInstance) { 32 | auto that = static_cast(bufferInstance); 33 | return that->getRawSlices().size(); 34 | } 35 | 36 | uint64_t BufferInstance_getRawSlices(void* bufferInstance, uint64_t max, GoBuf* dest) { 37 | auto that = static_cast(bufferInstance); 38 | 39 | auto len = 0; 40 | for (const auto& slice : that->getRawSlices(max)) { 41 | dest->data = slice.mem_; 42 | dest->len = dest->cap = slice.len_; 43 | dest++; 44 | len++; 45 | } 46 | return len; 47 | } 48 | -------------------------------------------------------------------------------- /ego/src/cc/goc/goc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 3 | // 4 | // Use of this source code is governed by the Apache License 2.0 that can be 5 | // found in the LICENSE file 6 | 7 | #ifndef CGO_GOC_H 8 | #define CGO_GOC_H 9 | 10 | #include "envoy/http/filter.h" 11 | #include "envoy/stats/stats.h" 12 | #include "envoy/stream_info/filter_state.h" 13 | 14 | // FilterStatus conversion 15 | Envoy::Http::FilterHeadersStatus Goc_FilterHeadersStatus(int status); 16 | Envoy::Http::FilterTrailersStatus Goc_FilterTrailersStatus(int status); 17 | Envoy::Http::FilterDataStatus Goc_FilterDataStatus(int status); 18 | // Http status code conversion 19 | Envoy::Http::Code Goc_HttpResonseCode(int responseCode); 20 | // FilterState enums conversion 21 | Envoy::StreamInfo::FilterState::StateType Goc_FilterStateType(int stateType); 22 | Envoy::StreamInfo::FilterState::LifeSpan Goc_FilterStateLifeSpan(int lifeSpan); 23 | // Stats enums conversion 24 | Envoy::Stats::Gauge::ImportMode Goc_Stats_ImportMode(int importMode); 25 | Envoy::Stats::Histogram::Unit Goc_Stats_Unit(int unit); 26 | int Goc_Stats_Unit_Value(Envoy::Stats::Histogram::Unit unit); 27 | 28 | #endif // CGO_GOC_H 29 | -------------------------------------------------------------------------------- /ego/src/cc/goc/log.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | #include "common/common/logger.h" 7 | 8 | #include "envoy.h" 9 | 10 | // Macro ENVOY_LOG_MISC and logger are declare inside Envoy namespace 11 | // So just wrapp it with a function extern "C" below 12 | namespace Envoy { 13 | 14 | void Envoy_log_misc(uint32_t level, absl::string_view tag, absl::string_view message) { 15 | switch (static_cast(level)) { 16 | case spdlog::level::trace: 17 | ENVOY_LOG_MISC(trace, "[ego_http][{}] {}", tag, message); 18 | return; 19 | case spdlog::level::debug: 20 | ENVOY_LOG_MISC(debug, "[ego_http][{}] {}", tag, message); 21 | return; 22 | case spdlog::level::info: 23 | ENVOY_LOG_MISC(info, "[ego_http][{}] {}", tag, message); 24 | return; 25 | case spdlog::level::warn: 26 | ENVOY_LOG_MISC(warn, "[ego_http][{}] {}", tag, message); 27 | return; 28 | case spdlog::level::err: 29 | ENVOY_LOG_MISC(error, "[ego_http][{}] {}", tag, message); 30 | return; 31 | case spdlog::level::critical: 32 | ENVOY_LOG_MISC(critical, "[ego_http][{}] {}", tag, message); 33 | return; 34 | case spdlog::level::off: 35 | return; 36 | } 37 | ENVOY_LOG_MISC(warn, "[ego_http][{}] UNDEFINED LOG LEVEL {}: {}", tag, level, message); 38 | } 39 | 40 | } // namespace Envoy 41 | 42 | void Envoy_log_misc(uint32_t level, GoStr tag, GoStr message) { 43 | auto c_message = absl::string_view(message.data, message.len); 44 | auto c_tag = absl::string_view(tag.data, tag.len); 45 | Envoy::Envoy_log_misc(level, c_tag, c_message); 46 | } 47 | -------------------------------------------------------------------------------- /ego/src/cc/goc/proto/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | # 3 | # Use of this source code is governed by the Apache License 2.0 that can be 4 | # found in the LICENSE file 5 | 6 | # gazelle:ignore 7 | 8 | load("@io_bazel_rules_go//proto:compiler.bzl", "go_proto_compiler") 9 | load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") 10 | load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") 11 | 12 | # This is generate proto for C-Side 13 | api_proto_package() 14 | 15 | # This is generate validation file 16 | go_proto_compiler( 17 | name = "pgv_plugin_go", 18 | options = ["lang=go"], 19 | plugin = "@com_envoyproxy_protoc_gen_validate//:protoc-gen-validate", 20 | suffix = ".pb.validate.go", 21 | valid_archive = False, 22 | ) 23 | 24 | # This is generate proto for G-Side usage 25 | go_proto_library( 26 | name = "go_default_library", 27 | compilers = [ 28 | "@io_bazel_rules_go//proto:go_proto", 29 | "pgv_plugin_go", 30 | ], 31 | importpath = "github.com/grab/ego/ego/src/cc/goc/proto", 32 | proto = ":pkg", # api_proto_package() generates this 33 | visibility = ["//visibility:public"], 34 | deps = [ 35 | "@com_envoyproxy_protoc_gen_validate//validate:go_default_library", 36 | "@com_github_golang_protobuf//ptypes:go_default_library", 37 | "@com_github_golang_protobuf//ptypes/any:go_default_library", 38 | "@com_github_golang_protobuf//ptypes/duration:go_default_library", 39 | "@com_github_golang_protobuf//ptypes/struct:go_default_library", 40 | "@com_github_golang_protobuf//ptypes/timestamp:go_default_library", 41 | "@com_github_golang_protobuf//ptypes/wrappers:go_default_library", 42 | "@com_google_googleapis//google/api:annotations_go_proto", 43 | "@com_google_googleapis//google/rpc:status_go_proto", 44 | ], 45 | ) 46 | -------------------------------------------------------------------------------- /ego/src/cc/goc/proto/dto.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | syntax = "proto3"; 7 | 8 | package ego.http; 9 | 10 | import "validate/validate.proto"; 11 | 12 | // TODO: will check replace it by HeaderMap below 13 | message RequestHeaderMap { 14 | repeated HeaderEntry headers = 1; 15 | } 16 | 17 | message ResponseHeaderMap { 18 | repeated HeaderEntry headers = 1; 19 | } 20 | 21 | message HeaderEntry { 22 | string key = 1; 23 | string value = 2; 24 | } -------------------------------------------------------------------------------- /ego/src/cc/goc/requesttrailermap.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | #include "envoy/http/header_map.h" 7 | 8 | #include "envoy.h" 9 | 10 | void RequestTrailerMap_add(void* requestTrailerMap, GoStr name, GoStr value) { 11 | 12 | auto that = static_cast(requestTrailerMap); 13 | 14 | // The std::string() constructor will create a copy of name. Unfortunately, 15 | // there is no std::string_view, because... 16 | auto c_name = std::string(name.data, name.len); 17 | 18 | // ...LowerCaseString creates a wrapped lowercase copy of c_name. 19 | auto w_name = Envoy::Http::LowerCaseString(c_name); 20 | 21 | // we are wrapping the header value with a lightweight string_view, which 22 | // is safe because... 23 | auto w_value = absl::string_view(value.data, value.len); 24 | 25 | // ...addCopy will add another header `w_name` associated with a copy of 26 | // `w_value` 27 | that->addCopy(w_name, w_value); 28 | } -------------------------------------------------------------------------------- /ego/src/cc/goc/stats.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | #include "envoy/stats/scope.h" 7 | 8 | #include "common/stats/symbol_table_impl.h" 9 | 10 | #include "envoy.h" 11 | #include "goc.h" 12 | 13 | // Stats::Scope 14 | // 15 | const void* Stats_Scope_counterFromStatName(void* scope, GoStr name) { 16 | auto ptr = static_cast(scope); 17 | auto w_name = absl::string_view(name.data, name.len); 18 | 19 | Envoy::Stats::StatNameManagedStorage storage(w_name, ptr->symbolTable()); 20 | Envoy::Stats::StatName stat_name = storage.statName(); 21 | 22 | auto c = &ptr->counterFromStatName(stat_name); 23 | return c; 24 | } 25 | 26 | const void* Stats_Scope_gaugeFromStatName(void* scope, GoStr name, int importMode) { 27 | auto ptr = static_cast(scope); 28 | auto w_name = absl::string_view(name.data, name.len); 29 | 30 | Envoy::Stats::StatNameManagedStorage storage(w_name, ptr->symbolTable()); 31 | Envoy::Stats::StatName stat_name = storage.statName(); 32 | 33 | auto c = &ptr->gaugeFromStatName(stat_name, Goc_Stats_ImportMode(importMode)); 34 | return c; 35 | } 36 | 37 | const void* Stats_Scope_histogramFromStatName(void* scope, GoStr name, int unit) { 38 | auto ptr = static_cast(scope); 39 | auto w_name = absl::string_view(name.data, name.len); 40 | 41 | Envoy::Stats::StatNameManagedStorage storage(w_name, ptr->symbolTable()); 42 | Envoy::Stats::StatName stat_name = storage.statName(); 43 | 44 | auto c = &ptr->histogramFromStatName(stat_name, Goc_Stats_Unit(unit)); 45 | return c; 46 | } 47 | 48 | // Stats::Counter 49 | // 50 | void Stats_Counter_add(void* counter, uint64_t amount) { 51 | auto ptr = static_cast(counter); 52 | ptr->add(amount); 53 | } 54 | 55 | void Stats_Counter_inc(void* counter) { 56 | auto ptr = static_cast(counter); 57 | ptr->inc(); 58 | } 59 | 60 | uint64_t Stats_Counter_latch(void* counter) { 61 | auto ptr = static_cast(counter); 62 | return ptr->latch(); 63 | } 64 | void Stats_Counter_reset(void* counter) { 65 | auto ptr = static_cast(counter); 66 | ptr->reset(); 67 | } 68 | uint64_t Stats_Counter_value(void* counter) { 69 | auto ptr = static_cast(counter); 70 | return ptr->value(); 71 | } 72 | 73 | // Stats::Gauge 74 | // 75 | void Stats_Gauge_add(void* gauge, uint64_t amount) { 76 | auto ptr = static_cast(gauge); 77 | ptr->add(amount); 78 | } 79 | 80 | void Stats_Gauge_dec(void* gauge) { 81 | auto ptr = static_cast(gauge); 82 | ptr->dec(); 83 | } 84 | 85 | void Stats_Gauge_inc(void* gauge) { 86 | auto ptr = static_cast(gauge); 87 | ptr->inc(); 88 | } 89 | 90 | void Stats_Gauge_set(void* gauge, uint64_t value) { 91 | auto ptr = static_cast(gauge); 92 | ptr->set(value); 93 | } 94 | 95 | void Stats_Gauge_sub(void* gauge, uint64_t amount) { 96 | auto ptr = static_cast(gauge); 97 | ptr->sub(amount); 98 | } 99 | 100 | uint64_t Stats_Gauge_value(void* gauge) { 101 | auto ptr = static_cast(gauge); 102 | return ptr->value(); 103 | } 104 | 105 | // Stats::Histogram 106 | int Stats_Histogram_unit(void* histogram) { 107 | auto ptr = static_cast(histogram); 108 | return Goc_Stats_Unit_Value(ptr->unit()); 109 | } 110 | 111 | void Stats_Histogram_recordValue(void* histogram, uint64_t value) { 112 | auto ptr = static_cast(histogram); 113 | ptr->recordValue(value); 114 | } -------------------------------------------------------------------------------- /ego/src/go/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | # 3 | # Use of this source code is governed by the Apache License 2.0 that can be 4 | # found in the LICENSE file 5 | 6 | load("@io_bazel_rules_go//go:def.bzl", "go_library") 7 | 8 | go_library( 9 | name = "go_default_library", 10 | srcs = [ 11 | "httpfilter.go", 12 | "registry.go", 13 | ], 14 | importpath = "github.com/grab/ego/ego/src/go", 15 | visibility = ["//visibility:public"], 16 | deps = [ 17 | "//ego/src/go/envoy:go_default_library", 18 | "//ego/src/go/envoy/datastatus:go_default_library", 19 | "//ego/src/go/envoy/headersstatus:go_default_library", 20 | "//ego/src/go/envoy/loglevel:go_default_library", 21 | "//ego/src/go/envoy/trailersstatus:go_default_library", 22 | "//ego/src/go/logger:go_default_library", 23 | "//ego/src/go/volatile:go_default_library", 24 | ], 25 | ) 26 | -------------------------------------------------------------------------------- /ego/src/go/README.md: -------------------------------------------------------------------------------- 1 | # Layout / Packages 2 | 3 | ## src/cc/filter 4 | 5 | An envoy filter dispatching to the go runtime. 6 | 7 | ## src/go 8 | 9 | A handful of Golang packages (`ego`) abstracting the interaction between Go code 10 | and the Envoy runtime. 11 | 12 | ### internal/cgo 13 | 14 | This package exists mostly because we have trouble linking CGO exports from 15 | multiple packages (). For the similar 16 | reasons, it contains the (unused) `main()` function. 17 | 18 | It contains all the CGO stubs for dispatching envoy filter callbacks to Go 19 | handlers. Since we need to avoid circular imports, we wrap all call-backs to 20 | the envoy runtime via interfaces declared in the [envoy](#envoy) package. 21 | 22 | This also simplifies development as all of these dependencies can be mocked. 23 | 24 | ### envoy 25 | 26 | This package abstracts all interactions with the C runtime. The interfaces are 27 | instantiated by the [cgo](#cgo) package, which can't be imported by the filter 28 | packages due to language and linker constraints. 29 | 30 | ### volatile 31 | 32 | This package exists mostly because `volatile.String` looks better than 33 | `envoy.VolatileString`. 34 | 35 | ### stub 36 | 37 | This package contains mocks for some of the interfaces defined in the 38 | [envoy](#envoy) package. This is useful for running unit tests without having 39 | to build envoy. 40 | -------------------------------------------------------------------------------- /ego/src/go/envoy/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | # 3 | # Use of this source code is governed by the Apache License 2.0 that can be 4 | # found in the LICENSE file 5 | 6 | load("@io_bazel_rules_go//go:def.bzl", "go_library") 7 | 8 | go_library( 9 | name = "go_default_library", 10 | srcs = ["envoy.go"], 11 | importpath = "github.com/grab/ego/ego/src/go/envoy", 12 | visibility = ["//visibility:public"], 13 | deps = [ 14 | "//ego/src/cc/goc/proto:go_default_library", 15 | "//ego/src/go/envoy/lifespan:go_default_library", 16 | "//ego/src/go/envoy/loglevel:go_default_library", 17 | "//ego/src/go/envoy/statetype:go_default_library", 18 | "//ego/src/go/envoy/stats:go_default_library", 19 | "//ego/src/go/volatile:go_default_library", 20 | ], 21 | ) 22 | -------------------------------------------------------------------------------- /ego/src/go/envoy/datastatus/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | # 3 | # Use of this source code is governed by the Apache License 2.0 that can be 4 | # found in the LICENSE file 5 | 6 | load("@io_bazel_rules_go//go:def.bzl", "go_library") 7 | 8 | go_library( 9 | name = "go_default_library", 10 | srcs = ["const.go"], 11 | importpath = "github.com/grab/ego/ego/src/go/envoy/datastatus", 12 | visibility = ["//visibility:public"], 13 | ) 14 | -------------------------------------------------------------------------------- /ego/src/go/envoy/datastatus/const.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package datastatus 7 | 8 | // Envoy::Http::FilterDataStatus 9 | // The constants have been chosen with arbtirary offsets to easier detect 10 | // return value type mismatches. 11 | // 12 | // see //envoy/include/envoy/http/filter.h 13 | 14 | type Type int 15 | const ( 16 | Continue Type = 300 17 | StopIterationAndBuffer Type = 301 18 | StopIterationAndWatermark Type = 302 19 | StopIterationNoBuffer Type = 303 20 | ) 21 | -------------------------------------------------------------------------------- /ego/src/go/envoy/headersstatus/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | # 3 | # Use of this source code is governed by the Apache License 2.0 that can be 4 | # found in the LICENSE file 5 | 6 | load("@io_bazel_rules_go//go:def.bzl", "go_library") 7 | 8 | go_library( 9 | name = "go_default_library", 10 | srcs = ["const.go"], 11 | importpath = "github.com/grab/ego/ego/src/go/envoy/headersstatus", 12 | visibility = ["//visibility:public"], 13 | ) 14 | -------------------------------------------------------------------------------- /ego/src/go/envoy/headersstatus/const.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package headersstatus 7 | 8 | // Envoy::Http::FilterHeadersStatus 9 | // The constants have been chosen with arbtirary offsets to easier detect 10 | // return value type mismatches. 11 | // 12 | // see //envoy/include/envoy/http/filter.h 13 | type Type int 14 | const ( 15 | Continue Type = 100 16 | StopIteration Type = 101 17 | ContinueAndEndStream Type = 102 18 | StopAllIterationAndBuffer Type = 103 19 | StopAllIterationAndWatermark Type = 104 20 | ) 21 | -------------------------------------------------------------------------------- /ego/src/go/envoy/lifespan/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | # 3 | # Use of this source code is governed by the Apache License 2.0 that can be 4 | # found in the LICENSE file 5 | 6 | load("@io_bazel_rules_go//go:def.bzl", "go_library") 7 | 8 | go_library( 9 | name = "go_default_library", 10 | srcs = ["const.go"], 11 | importpath = "github.com/grab/ego/ego/src/go/envoy/lifespan", 12 | visibility = ["//visibility:public"], 13 | ) 14 | -------------------------------------------------------------------------------- /ego/src/go/envoy/lifespan/const.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package lifespan 7 | 8 | // Envoy::StreamInfo::FilterState::LifeSpan 9 | // The constants have been chosen with arbtirary offsets to easier detect 10 | // return value type mismatches. 11 | // 12 | // see //envoy/include/envoy/stream_info/filter_state.h 13 | type Type int 14 | 15 | const ( 16 | FilterChain Type = 1 17 | DownstreamRequest Type = 2 18 | DownstreamConnection Type = 3 19 | TopSpan Type = 4 20 | ) 21 | -------------------------------------------------------------------------------- /ego/src/go/envoy/loglevel/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | # 3 | # Use of this source code is governed by the Apache License 2.0 that can be 4 | # found in the LICENSE file 5 | 6 | load("@io_bazel_rules_go//go:def.bzl", "go_library") 7 | 8 | go_library( 9 | name = "go_default_library", 10 | srcs = ["const.go"], 11 | importpath = "github.com/grab/ego/ego/src/go/envoy/loglevel", 12 | visibility = ["//visibility:public"], 13 | ) 14 | -------------------------------------------------------------------------------- /ego/src/go/envoy/loglevel/const.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package loglevel 7 | 8 | // spdlog::level::level_enum 9 | // 10 | // see https://github.com/gabime/spdlog/blob/master/include/spdlog/common.h#L78 11 | 12 | type Type int 13 | const ( 14 | Trace Type = 0 15 | Debug Type = 1 16 | Info Type = 2 17 | Warn Type = 3 18 | Error Type = 4 19 | Critical Type = 5 20 | ) 21 | -------------------------------------------------------------------------------- /ego/src/go/envoy/statetype/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | # 3 | # Use of this source code is governed by the Apache License 2.0 that can be 4 | # found in the LICENSE file 5 | 6 | load("@io_bazel_rules_go//go:def.bzl", "go_library") 7 | 8 | go_library( 9 | name = "go_default_library", 10 | srcs = ["const.go"], 11 | importpath = "github.com/grab/ego/ego/src/go/envoy/statetype", 12 | visibility = ["//visibility:public"], 13 | ) 14 | -------------------------------------------------------------------------------- /ego/src/go/envoy/statetype/const.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package statetype 7 | 8 | // Envoy::StreamInfo::FilterState::StateType 9 | // The constants have been chosen with arbtirary offsets to easier detect 10 | // return value type mismatches. 11 | // 12 | // see //envoy/include/envoy/stream_info/filter_state.h 13 | type Type int 14 | 15 | const ( 16 | ReadOnly Type = 1 17 | Mutable Type = 2 18 | ) 19 | -------------------------------------------------------------------------------- /ego/src/go/envoy/stats/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | # 3 | # Use of this source code is governed by the Apache License 2.0 that can be 4 | # found in the LICENSE file 5 | 6 | load("@io_bazel_rules_go//go:def.bzl", "go_library") 7 | 8 | go_library( 9 | name = "go_default_library", 10 | srcs = ["const.go"], 11 | importpath = "github.com/grab/ego/ego/src/go/envoy/stats", 12 | visibility = ["//visibility:public"], 13 | ) 14 | -------------------------------------------------------------------------------- /ego/src/go/envoy/stats/const.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package stats 7 | 8 | // see envoy/include/envoy/stats/stats.h 9 | 10 | // ImportMode for Gauge Metric 11 | type ImportMode int 12 | 13 | const ( 14 | // Uninitialized means Gauge was discovered during hot-restart transfer. 15 | Uninitialized ImportMode = 1 16 | // NeverImport means On hot-restart, each process starts with gauge at 0. 17 | NeverImport ImportMode = 2 18 | // Accumulate means Transfers gauge state on hot-restart. 19 | Accumulate ImportMode = 3 20 | ) 21 | 22 | // see envoy/include/envoy/stats/histogram.h 23 | 24 | // Unit for Histogram Metric 25 | type Unit int 26 | 27 | const ( 28 | // Null means The histogram has been rejected, i.e. it's a null histogram 29 | // and is not recording anything. 30 | Null Unit = 1 31 | // Unspecified means Measured quantity does not require a unit, e.g. "items". 32 | Unspecified Unit = 2 33 | // Bytes ... 34 | Bytes Unit = 3 35 | // Microseconds ... 36 | Microseconds Unit = 4 37 | // Milliseconds ... 38 | Milliseconds Unit = 5 39 | ) 40 | -------------------------------------------------------------------------------- /ego/src/go/envoy/trailersstatus/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | # 3 | # Use of this source code is governed by the Apache License 2.0 that can be 4 | # found in the LICENSE file 5 | 6 | load("@io_bazel_rules_go//go:def.bzl", "go_library") 7 | 8 | go_library( 9 | name = "go_default_library", 10 | srcs = ["const.go"], 11 | importpath = "github.com/grab/ego/ego/src/go/envoy/trailersstatus", 12 | visibility = ["//visibility:public"], 13 | ) 14 | -------------------------------------------------------------------------------- /ego/src/go/envoy/trailersstatus/const.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package trailersstatus 7 | 8 | // Envoy::Http::FilterTrailerStatus 9 | // The constants have been chosen with arbtirary offsets to easier detect 10 | // return value type mismatches. 11 | // 12 | // see //envoy/include/envoy/http/filter.h 13 | type Type int 14 | const ( 15 | Continue Type = 201 16 | StopIteration Type = 202 17 | ) 18 | -------------------------------------------------------------------------------- /ego/src/go/internal/cgo/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | # 3 | # Use of this source code is governed by the Apache License 2.0 that can be 4 | # found in the LICENSE file 5 | 6 | load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test") 7 | 8 | # Maintained by Gazelle. The only customisation is 9 | # `cdeps = ["//ego/src/cc/cgo:native"]`, which gives us access to the downcall 10 | # proxies and header file ("//ego/src/cc/cgo/envoy.h"). 11 | go_library( 12 | name = "go_default_library", 13 | srcs = [ 14 | "bufferinstance.go", 15 | "clutch.go", 16 | "cutils.go", 17 | "decoder_callbacks.go", 18 | "encoder_callbacks.go", 19 | "filter_state.go", 20 | "gohttpfilter.go", 21 | "gohttpfilterconfig.go", 22 | "logger.go", 23 | "main.go", 24 | "requestheadermap.go", 25 | "requesttrailermap.go", 26 | "responseheadermap.go", 27 | "route.go", 28 | "span.go", 29 | "stats.go", 30 | "stream_info.go", 31 | ], 32 | cdeps = ["//ego/src/cc/goc:goc"], 33 | cgo = True, 34 | importpath = "github.com/grab/ego/ego/src/go/internal/cgo", 35 | visibility = ["//visibility:private"], 36 | deps = [ 37 | "//ego/src/cc/goc/proto:go_default_library", 38 | "//ego/src/go:go_default_library", 39 | "//ego/src/go/envoy:go_default_library", 40 | "//ego/src/go/envoy/datastatus:go_default_library", 41 | "//ego/src/go/envoy/headersstatus:go_default_library", 42 | "//ego/src/go/envoy/lifespan:go_default_library", 43 | "//ego/src/go/envoy/loglevel:go_default_library", 44 | "//ego/src/go/envoy/statetype:go_default_library", 45 | "//ego/src/go/envoy/stats:go_default_library", 46 | "//ego/src/go/envoy/trailersstatus:go_default_library", 47 | "//ego/src/go/logger:go_default_library", 48 | "//ego/src/go/volatile:go_default_library", 49 | "//egofilters:go_default_library", 50 | "@com_github_golang_protobuf//proto:go_default_library", 51 | ], 52 | ) 53 | 54 | # :cgo contains the Go portions of our envoy extensions. 55 | go_binary( 56 | name = "cgo", 57 | cdeps = [ 58 | "//ego/src/cc/goc:goc", 59 | ], 60 | embed = [":go_default_library"], 61 | linkmode = "c-archive", 62 | visibility = ["//visibility:public"], 63 | ) 64 | 65 | go_test( 66 | name = "go_default_test", 67 | srcs = ["clutch_test.go"], 68 | embed = [":go_default_library"], 69 | importpath = "github.com/grab/ego/ego/src/go/internal/cgo", 70 | deps = [ 71 | "@com_github_stretchr_testify//assert:go_default_library", 72 | ], 73 | ) 74 | 75 | go_test( 76 | name = "go_clutch_test", 77 | srcs = [ 78 | "clutch.go", 79 | "clutch_test.go", 80 | ], 81 | cgo = True, 82 | importpath = "github.com/grab/ego/ego/src/go/internal/cgo", 83 | deps = [ 84 | "@com_github_stretchr_testify//assert:go_default_library", 85 | ], 86 | ) 87 | -------------------------------------------------------------------------------- /ego/src/go/internal/cgo/bufferinstance.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package main 7 | 8 | // #include "ego/src/cc/goc/envoy.h" 9 | import "C" 10 | import ( 11 | "io" 12 | "unsafe" 13 | 14 | "github.com/grab/ego/ego/src/go/volatile" 15 | ) 16 | 17 | // bufferInstance implements envoy.BufferInstance 18 | // 19 | type bufferInstance struct { 20 | ptr unsafe.Pointer 21 | } 22 | 23 | func (b bufferInstance) CopyOut(start uint64, dest []byte) int { 24 | return int(C.BufferInstance_copyOut(b.ptr, C.size_t(start), GoBuf(dest))) 25 | } 26 | 27 | func (b bufferInstance) GetRawSlices() []volatile.Bytes { 28 | 29 | // FIXME: since this is not thread safe, we could just buffer the result 30 | // for BufferInstance_getRawSlices to pick it up without having to 31 | // call getRawSlices a second time... 32 | max := int(C.BufferInstance_getRawSlicesCount(b.ptr)) 33 | if 0 == max { 34 | return nil 35 | } 36 | 37 | temp := make([]C.GoBuf, max) 38 | count := int(C.BufferInstance_getRawSlices(b.ptr, C.uint64_t(max), &temp[0])) 39 | dest := make([]volatile.Bytes, count) 40 | for i := 0; i < count; i++ { 41 | dest[i] = CBytes(temp[i].data, temp[i].len, temp[i].cap) 42 | } 43 | return dest 44 | } 45 | 46 | func (b bufferInstance) Length() uint64 { 47 | return uint64(C.BufferInstance_length(b.ptr)) 48 | } 49 | 50 | func (b bufferInstance) NewReader(start uint64) io.Reader { 51 | return &bufferInstanceReader{bufferInstance: b, pos: start} 52 | } 53 | 54 | type bufferInstanceReader struct { 55 | bufferInstance 56 | pos uint64 57 | } 58 | 59 | func (r *bufferInstanceReader) Read(p []byte) (n int, err error) { 60 | if 0 < len(p) { 61 | if n = r.CopyOut(r.pos, p); n <= 0 { 62 | err = io.EOF 63 | } else { 64 | r.pos += uint64(n) 65 | } 66 | } 67 | return 68 | } 69 | -------------------------------------------------------------------------------- /ego/src/go/internal/cgo/cutils.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package main 7 | 8 | //#include 9 | //#include "ego/src/cc/goc/envoy.h" 10 | import "C" 11 | import ( 12 | "errors" 13 | "math" 14 | "reflect" 15 | "unsafe" 16 | 17 | "github.com/grab/ego/ego/src/go/volatile" 18 | ) 19 | 20 | // GoStr create an unsafe reference to a Go string for passing it down to C++ 21 | // 22 | func GoStr(s string) C.GoStr { 23 | h := (*reflect.StringHeader)(unsafe.Pointer(&s)) 24 | return C.GoStr{ 25 | len: C.ulong(h.Len), 26 | data: (*C.char)(unsafe.Pointer(h.Data)), 27 | } 28 | } 29 | 30 | // GoBuf create an unsafe reference to a Go byte array for passing it down to C++ 31 | // 32 | func GoBuf(b []byte) C.GoBuf { 33 | h := (*reflect.SliceHeader)(unsafe.Pointer(&b)) 34 | return C.GoBuf{ 35 | len: C.ulong(h.Len), 36 | cap: C.ulong(h.Cap), 37 | data: unsafe.Pointer(h.Data), 38 | } 39 | } 40 | 41 | // We have agreed on a sweet little convention for returning errors 42 | // from C++ land: static, constant C strings. CErr wraps them into a 43 | // Go error. 44 | // 45 | func CErr(ptr *C.char) error { 46 | if nil == ptr { 47 | return nil 48 | } 49 | return errors.New(string(CStr(ptr))) 50 | } 51 | 52 | // CStr is very dangerous, because if the returned string slice escapes, 53 | // its contents may be modified later. If you are unsure, do use C.GoString. 54 | // 55 | func CStr(ptr *C.char) volatile.String { 56 | 57 | // prevent null pointer access 58 | if nil == ptr { 59 | return "" 60 | } 61 | 62 | return CStrN(ptr, C.strlen(ptr)) 63 | } 64 | 65 | // CStrN is very dangerous, because if the returned string slice escapes, 66 | // its contents may be modified later. If you are unsure, do use C.GoStringN. 67 | // 68 | func CStrN(ptr *C.char, n C.size_t) volatile.String { 69 | 70 | // prevent null pointer access 71 | if nil == ptr { 72 | if 0 != n { 73 | panic("C string is null") 74 | } 75 | return "" 76 | } 77 | 78 | // ensure no loss occurs during conversion. 79 | if n != C.size_t(int(n)) || int(n) < 0 { 80 | panic("C string too long") 81 | } 82 | h := reflect.StringHeader{uintptr(unsafe.Pointer(ptr)), int(n)} 83 | return *(*volatile.String)(unsafe.Pointer(&h)) 84 | } 85 | 86 | // CBytes is very dangerous, because if the returned byte slice escapes, 87 | // its contents may be modified later. If you are unsure, do use C.GoBytes. 88 | // 89 | func CBytes(ptr unsafe.Pointer, size, cap C.size_t) volatile.Bytes { 90 | 91 | // The maximum address space can be larger than 4GB. Apparently, 50bits are 92 | // supported for 64bit architectures, so we bump up the value in that case. 93 | const maxCap = int(math.MaxInt32) | int((^uint(0))>>14) 94 | 95 | // ensure no loss occurs during conversion and capacity isn't too large 96 | if C.size_t(int(cap)) != cap || int(cap) < 0 || maxCap < int(cap) { 97 | panic("C buffer too large") 98 | } 99 | if C.size_t(int(size)) != size || int(size) < 0 || int(cap) < int(size) { 100 | panic("Invalid C buffer") 101 | } 102 | // https://github.com/golang/go/wiki/cgo#turning-c-arrays-into-go-slices 103 | return volatile.Bytes((*[maxCap]byte)(ptr)[:size:int(cap)]) 104 | } 105 | 106 | func CLong(val C.int64_t) int64 { 107 | return int64(val) 108 | } 109 | 110 | func GoBool(val bool) C.int { 111 | if val { 112 | return C.int(1) 113 | } 114 | return C.int(0) 115 | } 116 | -------------------------------------------------------------------------------- /ego/src/go/internal/cgo/encoder_callbacks.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package main 7 | 8 | // #include "ego/src/cc/goc/envoy.h" 9 | import "C" 10 | import ( 11 | "unsafe" 12 | 13 | "github.com/grab/ego/ego/src/go/envoy" 14 | ) 15 | 16 | type encoderCallbacks struct { 17 | filter unsafe.Pointer 18 | } 19 | 20 | // This section is implementation downcalls for StreamEncoderFilterCallbacks 21 | // 22 | // See //envoy/include/envoy/http/filter.h 23 | func (c encoderCallbacks) EncodingBuffer() envoy.BufferInstance { 24 | ptr := C.GoHttpFilter_EncoderCallbacks_encodingBuffer(c.filter) 25 | if ptr == nil { 26 | return nil 27 | } 28 | 29 | return bufferInstance{ptr} 30 | } 31 | 32 | // See //envoy/include/envoy/http/filter.h 33 | func (c encoderCallbacks) AddEncodedData(buffer envoy.BufferInstance, streamingFilter bool) { 34 | if buffer == nil { 35 | return 36 | } 37 | 38 | var streamingFilterInt int8 39 | if streamingFilter { 40 | streamingFilterInt = 1 41 | } 42 | 43 | b := buffer.(bufferInstance) 44 | C.GoHttpFilter_EncoderCallbacks_addEncodedData(c.filter, b.ptr, C.int(streamingFilterInt)) 45 | } 46 | 47 | // See //envoy/include/envoy/http/filter.h 48 | func (c encoderCallbacks) ContinueEncoding() { 49 | C.GoHttpFilter_EncoderCallbacks_continueEncoding(c.filter) 50 | } 51 | 52 | func (c encoderCallbacks) StreamInfo() envoy.StreamInfo { 53 | return &streamInfo{c.filter, true} 54 | } 55 | 56 | func (c encoderCallbacks) RouteExisting() bool { 57 | existing := C.GoHttpFilter_StreamFilterCallbacks_routeExisting(c.filter, GoBool(true)) 58 | return existing != 0 59 | } 60 | 61 | func (c encoderCallbacks) Route() envoy.Route { 62 | return &route{c.filter, true} 63 | } 64 | 65 | func (c encoderCallbacks) ActiveSpan() envoy.Span { 66 | return span{filter: c.filter, spanID: 0} 67 | } 68 | -------------------------------------------------------------------------------- /ego/src/go/internal/cgo/filter_state.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package main 7 | 8 | // #include "ego/src/cc/goc/envoy.h" 9 | import "C" 10 | import ( 11 | "unsafe" 12 | 13 | "github.com/grab/ego/ego/src/go/envoy/lifespan" 14 | "github.com/grab/ego/ego/src/go/envoy/statetype" 15 | "github.com/grab/ego/ego/src/go/volatile" 16 | ) 17 | 18 | type filterState struct { 19 | filter unsafe.Pointer 20 | encoder bool 21 | } 22 | 23 | func (s filterState) SetData(name, value string, stateType statetype.Type, lifeSpan lifespan.Type) { 24 | C.GoHttpFilter_DecoderCallbacks_StreamInfo_FilterState_setData(s.filter, GoStr(name), GoStr(value), C.int(stateType), C.int(lifeSpan)) 25 | } 26 | 27 | func (s filterState) GetDataReadOnly(name string) (volatile.String, bool) { 28 | var value C.GoStr 29 | ok := C.GoHttpFilter_StreamFilterCallbacks_StreamInfo_FilterState_getDataReadOnly(s.filter, GoBool(s.encoder), GoStr(name), &value) 30 | return CStrN(value.data, value.len), ok != 0 31 | } 32 | -------------------------------------------------------------------------------- /ego/src/go/internal/cgo/logger.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package main 7 | 8 | // #include "ego/src/cc/goc/envoy.h" 9 | import "C" 10 | 11 | import ( 12 | "github.com/grab/ego/ego/src/go/envoy/loglevel" 13 | ) 14 | 15 | // Log is a basic log function and base on that developers can extend or write their logger 16 | func Log(level loglevel.Type, tag, message string) { 17 | C.Envoy_log_misc(C.uint32_t(level), GoStr(tag), GoStr(message)) 18 | } 19 | 20 | type nativeLogger struct { 21 | } 22 | 23 | func (l nativeLogger) Log(level loglevel.Type, tag, message string) { 24 | Log(level, tag, message) 25 | } 26 | -------------------------------------------------------------------------------- /ego/src/go/internal/cgo/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package main 7 | 8 | import ( 9 | logger "github.com/grab/ego/ego/src/go/logger" 10 | 11 | // This is a rather ugly. We can't use ego as a dependency of egofilters 12 | // because main() needs to be located in the same package as the cgo code, 13 | // and there can only be one package with cgo code (at least when building 14 | // with bazel). 15 | _ "github.com/grab/ego/egofilters" 16 | ) 17 | 18 | func init() { 19 | 20 | logger.Init(nativeLogger{}) 21 | 22 | // FIXME: To be super safe, we should probably say "hi" before accepting 23 | // CGo calls: https://github.com/golang/go/issues/15943#issuecomment-713153486 24 | } 25 | 26 | // main() is not used -- this is a static library. 27 | func main() { 28 | 29 | } 30 | -------------------------------------------------------------------------------- /ego/src/go/internal/cgo/requestheadermap.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package main 7 | 8 | // #include "ego/src/cc/goc/envoy.h" 9 | import "C" 10 | import ( 11 | "unsafe" 12 | 13 | "github.com/golang/protobuf/proto" 14 | 15 | pb "github.com/grab/ego/ego/src/cc/goc/proto" 16 | "github.com/grab/ego/ego/src/go/volatile" 17 | ) 18 | 19 | // requestheadermap implements envoy.RequestHeaderMap 20 | // 21 | type requestHeaderMap struct{ ptr unsafe.Pointer } 22 | 23 | // AddCopy translates to 24 | // Envoy::Http::RequestHeaderMap::addCopy(LowerCaseString, absl::string_view). 25 | // 26 | // See //envoy/include/envoy/http/header_map.h 27 | func (h requestHeaderMap) AddCopy(name, value string) { 28 | C.RequestHeaderMap_add(h.ptr, GoStr(name), GoStr(value)) 29 | } 30 | 31 | // SetCopy translates to 32 | // Envoy::Http::RequestHeaderMap::setCopy(LowerCaseString, absl::string_view). 33 | // 34 | // See //envoy/include/envoy/http/header_map.h 35 | func (h requestHeaderMap) SetCopy(name, value string) { 36 | C.RequestHeaderMap_set(h.ptr, GoStr(name), GoStr(value)) 37 | } 38 | 39 | // AppendCopy translates to 40 | // Envoy::Http::RequestHeaderMap::appendCopy(LowerCaseString, absl::string_view). 41 | // 42 | // See //envoy/include/envoy/http/header_map.h 43 | func (h requestHeaderMap) AppendCopy(name, value string) { 44 | C.RequestHeaderMap_append(h.ptr, GoStr(name), GoStr(value)) 45 | } 46 | 47 | func (h requestHeaderMap) GetByPrefix(prefix string) map[string][]string { 48 | defaultBufferSize := uint64(100) 49 | data := make([]byte, defaultBufferSize) 50 | size := uint64(C.RequestHeaderMap_getByPrefix(h.ptr, GoStr(prefix), GoBuf(data))) 51 | if size > defaultBufferSize { 52 | newBufferSize := size 53 | data = make([]byte, newBufferSize) 54 | size = uint64(C.RequestHeaderMap_getByPrefix(h.ptr, GoStr(prefix), GoBuf(data))) 55 | if size > newBufferSize { 56 | // it's not supposed to happen. 57 | panic("Invalid logic") 58 | } 59 | } 60 | headers := pb.RequestHeaderMap{} 61 | if err := proto.Unmarshal(data[:size], &headers); err != nil { 62 | // TODO: handle error 63 | } 64 | 65 | result := make(map[string][]string) 66 | for _, h := range headers.Headers { 67 | if _, existing := result[h.Key]; !existing { 68 | result[h.Key] = []string{h.Value} 69 | } 70 | } 71 | 72 | return result 73 | } 74 | 75 | // Remove translates to 76 | // Envoy::Http::RequestHeaderMap::remove(LowerCaseString). 77 | // 78 | // See //envoy/include/envoy/http/header_map.h 79 | func (h requestHeaderMap) Remove(name string) { 80 | C.RequestHeaderMap_remove(h.ptr, GoStr(name)) 81 | } 82 | 83 | func (h requestHeaderMap) Path() volatile.String { 84 | var value C.GoStr 85 | C.RequestHeaderMap_Path(h.ptr, &value) 86 | return CStrN(value.data, value.len) 87 | } 88 | 89 | func (h requestHeaderMap) SetPath(path string) { 90 | C.RequestHeaderMap_setPath(h.ptr, GoStr(path)) 91 | } 92 | 93 | func (h requestHeaderMap) Method() volatile.String { 94 | var value C.GoStr 95 | C.RequestHeaderMap_Method(h.ptr, &value) 96 | return CStrN(value.data, value.len) 97 | } 98 | 99 | func (h requestHeaderMap) Authorization() volatile.String { 100 | var value C.GoStr 101 | C.RequestHeaderMap_Authorization(h.ptr, &value) 102 | return CStrN(value.data, value.len) 103 | } 104 | 105 | func (h requestHeaderMap) ContentType() volatile.String { 106 | var value C.GoStr 107 | C.RequestHeaderMap_ContentType(h.ptr, &value) 108 | return CStrN(value.data, value.len) 109 | } 110 | 111 | func (h requestHeaderMap) Get(name string) volatile.String { 112 | var value C.GoStr 113 | C.RequestHeaderMap_get(h.ptr, GoStr(name), &value) 114 | return CStrN(value.data, value.len) 115 | } 116 | -------------------------------------------------------------------------------- /ego/src/go/internal/cgo/requesttrailermap.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package main 7 | 8 | // #include "ego/src/cc/goc/envoy.h" 9 | import "C" 10 | import ( 11 | "unsafe" 12 | 13 | "github.com/grab/ego/ego/src/go/volatile" 14 | ) 15 | 16 | // requestheadermap implements envoy.RequestHeaderMap 17 | // 18 | type requestTrailerMap struct{ ptr unsafe.Pointer } 19 | 20 | // AddCopy translates to 21 | // Envoy::Http::RequestHeaderMap::addCopy(LowerCaseString, absl::string_view). 22 | // 23 | // See //envoy/include/envoy/http/header_map.h 24 | func (h requestTrailerMap) AddCopy(name, value string) { 25 | C.RequestTrailerMap_add(h.ptr, GoStr(name), GoStr(value)) 26 | } 27 | 28 | func (h requestTrailerMap) SetCopy(name, value string) { 29 | panic("Not implemented yet") 30 | } 31 | 32 | func (h requestTrailerMap) AppendCopy(name, value string) { 33 | panic("Not implemented yet") 34 | } 35 | 36 | func (h requestTrailerMap) Remove(name string) { 37 | panic("Not implemented yet") 38 | } 39 | 40 | func (h requestTrailerMap) Get(name string) volatile.String { 41 | panic("Not implemented yet") 42 | return volatile.String("") 43 | } 44 | 45 | func (h requestTrailerMap) GetByPrefix(prefix string) map[string][]string { 46 | panic("Not implemented yet") 47 | return map[string][]string{} 48 | } 49 | -------------------------------------------------------------------------------- /ego/src/go/internal/cgo/responseheadermap.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package main 7 | 8 | // #include "ego/src/cc/goc/envoy.h" 9 | import "C" 10 | import ( 11 | "unsafe" 12 | 13 | "github.com/grab/ego/ego/src/go/volatile" 14 | ) 15 | 16 | // responseHeaderMap implements envoy.ResponseHeaderMap 17 | // 18 | type responseHeaderMap struct{ ptr unsafe.Pointer } 19 | 20 | // AddCopy translates to 21 | // Envoy::Http::ResponseHeaderMap::addCopy(LowerCaseString, absl::string_view). 22 | // 23 | // See //envoy/include/envoy/http/header_map.h 24 | func (h responseHeaderMap) AddCopy(name, value string) { 25 | C.ResponseHeaderMap_add(h.ptr, GoStr(name), GoStr(value)) 26 | } 27 | 28 | // SetCopy translates to 29 | // Envoy::Http::ResponseHeaderMap::setCopy(LowerCaseString, absl::string_view). 30 | // 31 | // See //envoy/include/envoy/http/header_map.h 32 | func (h responseHeaderMap) SetCopy(name, value string) { 33 | C.ResponseHeaderMap_set(h.ptr, GoStr(name), GoStr(value)) 34 | } 35 | 36 | // AppendCopy translates to 37 | // Envoy::Http::ResponseHeaderMap::appendCopy(LowerCaseString, absl::string_view). 38 | // 39 | // See //envoy/include/envoy/http/header_map.h 40 | func (h responseHeaderMap) AppendCopy(name, value string) { 41 | C.ResponseHeaderMap_append(h.ptr, GoStr(name), GoStr(value)) 42 | } 43 | 44 | // Remove translates to 45 | // Envoy::Http::ResponseHeaderMap::remove(LowerCaseString). 46 | // 47 | // See //envoy/include/envoy/http/header_map.h 48 | func (h responseHeaderMap) Remove(name string) { 49 | C.ResponseHeaderMap_remove(h.ptr, GoStr(name)) 50 | } 51 | 52 | // ContentType translates to 53 | // Envoy::Http::ResponseHeaderMap::ContentType(). 54 | // 55 | // See //envoy/include/envoy/http/header_map.h 56 | func (h responseHeaderMap) ContentType() volatile.String { 57 | var value C.GoStr 58 | C.ResponseHeaderMap_ContentType(h.ptr, &value) 59 | return CStrN(value.data, value.len) 60 | } 61 | 62 | // Status translates to 63 | // Envoy::Http::ResponseHeaderMap::Status(). 64 | // 65 | // See //envoy/include/envoy/http/header_map.h 66 | func (h responseHeaderMap) Status() volatile.String { 67 | var value C.GoStr 68 | C.ResponseHeaderMap_Status(h.ptr, &value) 69 | return CStrN(value.data, value.len) 70 | } 71 | 72 | // SetStatus translates to 73 | // Envoy::Http::ResponseHeaderMap::setStatus(uint64_t). 74 | // 75 | // See //envoy/include/envoy/http/header_map.h 76 | func (h responseHeaderMap) SetStatus(status int) { 77 | C.ResponseHeaderMap_setStatus(h.ptr, C.int(status)) 78 | 79 | } 80 | 81 | // Get translates to 82 | // Envoy::Http::ResponseHeaderMap::Get(LowerCaseString). 83 | // 84 | // See //envoy/include/envoy/http/header_map.h 85 | func (h responseHeaderMap) Get(name string) volatile.String { 86 | var value C.GoStr 87 | C.ResponseHeaderMap_get(h.ptr, GoStr(name), &value) 88 | return CStrN(value.data, value.len) 89 | } 90 | -------------------------------------------------------------------------------- /ego/src/go/internal/cgo/route.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package main 7 | 8 | // #include "ego/src/cc/goc/envoy.h" 9 | import "C" 10 | import ( 11 | "fmt" 12 | "unsafe" 13 | 14 | "github.com/grab/ego/ego/src/go/envoy" 15 | "github.com/grab/ego/ego/src/go/volatile" 16 | ) 17 | 18 | type route struct { 19 | filter unsafe.Pointer 20 | encoder bool 21 | } 22 | 23 | func (r *route) RouteEntry() envoy.RouteEntry { 24 | return &routeEntry{r.filter, r.encoder} 25 | } 26 | 27 | type routeEntry struct { 28 | filter unsafe.Pointer 29 | encoder bool 30 | } 31 | 32 | func (e *routeEntry) PathMatchCriterion() envoy.PathMatchCriterion { 33 | return &pathMatchCriterion{e.filter, e.encoder} 34 | } 35 | 36 | type pathMatchCriterion struct { 37 | filter unsafe.Pointer 38 | encoder bool 39 | } 40 | 41 | func (c *pathMatchCriterion) MatchType() (envoy.PathMatchType, error) { 42 | matchType := C.GoHttpFilter_StreamFilterCallbacks_route_routeEntry_pathMatchCriterion_matchType(c.filter, GoBool(c.encoder)) 43 | switch matchType { 44 | case 0: 45 | return envoy.PathMatchNone, nil 46 | case 1: 47 | return envoy.PathMatchPrefix, nil 48 | case 2: 49 | return envoy.PathMatchExact, nil 50 | case 3: 51 | return envoy.PathMatchRegex, nil 52 | } 53 | return envoy.PathMatchNone, fmt.Errorf("invalid match type of %v", matchType) 54 | } 55 | 56 | func (c *pathMatchCriterion) Matcher() (volatile.String, error) { 57 | var value C.GoStr 58 | errCode := C.GoHttpFilter_StreamFilterCallbacks_route_routeEntry_pathMatchCriterion_matcher(c.filter, GoBool(c.encoder), &value) 59 | if errCode != 0 { 60 | return volatile.String(""), fmt.Errorf("can't get matcher. error code %d", errCode) 61 | } 62 | 63 | return CStrN(value.data, value.len), nil 64 | } 65 | -------------------------------------------------------------------------------- /ego/src/go/internal/cgo/span.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package main 7 | 8 | // #include "ego/src/cc/goc/envoy.h" 9 | import "C" 10 | 11 | import ( 12 | "unsafe" 13 | 14 | "github.com/golang/protobuf/proto" 15 | 16 | pb "github.com/grab/ego/ego/src/cc/goc/proto" 17 | "github.com/grab/ego/ego/src/go/envoy" 18 | ) 19 | 20 | type span struct { 21 | filter unsafe.Pointer 22 | spanID int64 23 | } 24 | 25 | func (s span) GetContext() map[string][]string { 26 | defaultBufferSize := uint64(100) 27 | data := make([]byte, defaultBufferSize) 28 | size := uint64(C.GoHttpFilter_Span_getContext(s.filter, C.long(s.spanID), GoBuf(data))) 29 | if size > defaultBufferSize { 30 | newBufferSize := size 31 | data = make([]byte, newBufferSize) 32 | size = uint64(C.GoHttpFilter_Span_getContext(s.filter, C.long(s.spanID), GoBuf(data))) 33 | if size > newBufferSize { 34 | // it's not supposed to happen. 35 | panic("Invalid logic") 36 | } 37 | } 38 | headers := pb.RequestHeaderMap{} 39 | if err := proto.Unmarshal(data[:size], &headers); err != nil { 40 | // TODO: handle error 41 | } 42 | 43 | result := make(map[string][]string) 44 | for _, h := range headers.Headers { 45 | if _, existing := result[h.Key]; !existing { 46 | result[h.Key] = []string{h.Value} 47 | } 48 | } 49 | 50 | return result 51 | } 52 | 53 | func (s span) SpawnChild(name string) envoy.Span { 54 | spanID := C.GoHttpFilter_Span_spawnChild(s.filter, C.long(s.spanID), GoStr(name)) 55 | return span{filter: s.filter, spanID: int64(spanID)} 56 | } 57 | 58 | func (s span) FinishSpan() { 59 | C.GoHttpFilter_Span_finishSpan(s.filter, C.long(s.spanID)) 60 | } 61 | -------------------------------------------------------------------------------- /ego/src/go/internal/cgo/stats.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package main 7 | 8 | // #include "ego/src/cc/goc/envoy.h" 9 | import "C" 10 | import ( 11 | "unsafe" 12 | 13 | "github.com/grab/ego/ego/src/go/envoy" 14 | "github.com/grab/ego/ego/src/go/envoy/stats" 15 | ) 16 | 17 | type scope struct { 18 | ptr unsafe.Pointer 19 | } 20 | 21 | func (s scope) CounterFromStatName(name string) envoy.Counter { 22 | ptr := C.Stats_Scope_counterFromStatName(s.ptr, GoStr(name)) 23 | if ptr == nil { 24 | return nil 25 | } 26 | return counter{ptr} 27 | } 28 | 29 | func (s scope) GaugeFromStatName(name string, importMode stats.ImportMode) envoy.Gauge { 30 | ptr := C.Stats_Scope_gaugeFromStatName(s.ptr, GoStr(name), C.int(importMode)) 31 | if ptr == nil { 32 | return nil 33 | } 34 | return gauge{ptr} 35 | } 36 | 37 | func (s scope) HistogramFromStatName(name string, unit stats.Unit) envoy.Histogram { 38 | ptr := C.Stats_Scope_histogramFromStatName(s.ptr, GoStr(name), C.int(unit)) 39 | if ptr == nil { 40 | return nil 41 | } 42 | return histogram{ptr} 43 | } 44 | 45 | type counter struct { 46 | ptr unsafe.Pointer 47 | } 48 | 49 | func (c counter) Add(amount uint64) { 50 | C.Stats_Counter_add(c.ptr, C.uint64_t(amount)) 51 | } 52 | 53 | func (c counter) Inc() { 54 | C.Stats_Counter_inc(c.ptr) 55 | } 56 | 57 | func (c counter) Latch() uint64 { 58 | return uint64(C.Stats_Counter_latch(c.ptr)) 59 | } 60 | 61 | func (c counter) Reset() { 62 | C.Stats_Counter_reset(c.ptr) 63 | } 64 | 65 | func (c counter) Value() uint64 { 66 | return uint64(C.Stats_Counter_value(c.ptr)) 67 | 68 | } 69 | 70 | type gauge struct { 71 | ptr unsafe.Pointer 72 | } 73 | 74 | func (g gauge) Add(amount uint64) { 75 | C.Stats_Gauge_add(g.ptr, C.uint64_t(amount)) 76 | } 77 | 78 | func (g gauge) Dec() { 79 | C.Stats_Gauge_dec(g.ptr) 80 | } 81 | 82 | func (g gauge) Inc() { 83 | C.Stats_Gauge_inc(g.ptr) 84 | } 85 | 86 | func (g gauge) Set(value uint64) { 87 | C.Stats_Gauge_set(g.ptr, C.uint64_t(value)) 88 | } 89 | 90 | func (g gauge) Sub(amount uint64) { 91 | C.Stats_Gauge_sub(g.ptr, C.uint64_t(amount)) 92 | } 93 | 94 | func (g gauge) Value() uint64 { 95 | return uint64(C.Stats_Gauge_value(g.ptr)) 96 | } 97 | 98 | type histogram struct { 99 | ptr unsafe.Pointer 100 | } 101 | 102 | func (h histogram) Unit() stats.Unit { 103 | return stats.Unit(C.Stats_Histogram_unit(h.ptr)) 104 | } 105 | 106 | func (h histogram) RecordValue(value uint64) { 107 | C.Stats_Histogram_recordValue(h.ptr, C.uint64_t(value)) 108 | } 109 | -------------------------------------------------------------------------------- /ego/src/go/internal/cgo/stream_info.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package main 7 | 8 | // #include "ego/src/cc/goc/envoy.h" 9 | import "C" 10 | import ( 11 | "unsafe" 12 | 13 | "github.com/grab/ego/ego/src/go/envoy" 14 | "github.com/grab/ego/ego/src/go/volatile" 15 | ) 16 | 17 | type streamInfo struct { 18 | filter unsafe.Pointer 19 | encoder bool 20 | } 21 | 22 | func (i streamInfo) FilterState() envoy.FilterState { 23 | return filterState{i.filter, i.encoder} 24 | } 25 | 26 | func (i streamInfo) LastDownstreamTxByteSent() int64 { 27 | return CLong(C.GoHttpFilter_StreamFilterCallbacks_StreamInfo_lastDownstreamTxByteSent(i.filter, GoBool(i.encoder))) 28 | } 29 | 30 | func (i streamInfo) GetRequestHeaders() envoy.RequestHeaderMapReadOnly { 31 | ptr := C.GoHttpFilter_StreamFilterCallbacks_StreamInfo_getRequestHeaders(i.filter, GoBool(i.encoder)) 32 | if ptr == nil { 33 | return nil 34 | } 35 | return &requestHeaderMap{ptr} 36 | } 37 | 38 | func (i streamInfo) ResponseCode() int { 39 | return int(C.GoHttpFilter_StreamFilterCallbacks_StreamInfo_responseCode(i.filter, GoBool(i.encoder))) 40 | } 41 | 42 | func (i streamInfo) ResponseCodeDetails() volatile.String { 43 | var value C.GoStr 44 | C.GoHttpFilter_StreamFilterCallbacks_StreamInfo_responseCodeDetails(i.filter, GoBool(i.encoder), &value) 45 | return CStrN(value.data, value.len) 46 | } 47 | -------------------------------------------------------------------------------- /ego/src/go/logger/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | # 3 | # Use of this source code is governed by the Apache License 2.0 that can be 4 | # found in the LICENSE file 5 | 6 | load("@io_bazel_rules_go//go:def.bzl", "go_library") 7 | 8 | go_library( 9 | name = "go_default_library", 10 | srcs = ["logger.go"], 11 | importpath = "github.com/grab/ego/ego/src/go/logger", 12 | visibility = ["//visibility:public"], 13 | deps = ["//ego/src/go/envoy/loglevel:go_default_library"], 14 | ) 15 | -------------------------------------------------------------------------------- /ego/src/go/logger/logger.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package logger 7 | 8 | import ( 9 | "fmt" 10 | 11 | "github.com/grab/ego/ego/src/go/envoy/loglevel" 12 | ) 13 | 14 | // Logger is an interface to encourage developers using this interface 15 | type Logger interface { 16 | Trace(message string, data ...interface{}) 17 | Debug(message string, data ...interface{}) 18 | Info(message string, data ...interface{}) 19 | Warn(message string, data ...interface{}) 20 | Error(message string, data ...interface{}) 21 | Critical(message string, data ...interface{}) 22 | // TODO: Fatal just like Critical but include throw exception on C, not implmeneted yet 23 | } 24 | 25 | // Configure as neeeded for your log aggregator... 26 | var Render func(string, ...interface{}) string = func(message string, data ...interface{}) string { 27 | if 0 < len(data) { 28 | message += fmt.Sprintf(" %+v", data) 29 | } 30 | return message 31 | } 32 | 33 | // Data is an alias to make easier using Log function 34 | type Data map[string]interface{} 35 | 36 | // NewLogger with utility wrapper log level & tag 37 | func NewLogger(tag string, native NativeLogger) Logger { 38 | finalNativeLogger := native 39 | if finalNativeLogger == nil { 40 | finalNativeLogger = defaultLogger 41 | } 42 | return envoyLogger{tag: tag, native: finalNativeLogger} 43 | } 44 | 45 | // NewDefaultLogger with utility wrapper log level & tag 46 | func NewDefaultLogger(tag string) Logger { 47 | return envoyLogger{tag: tag, native: defaultLogger} 48 | } 49 | 50 | var defaultLogger NativeLogger 51 | 52 | func Init(native NativeLogger) { 53 | defaultLogger = native 54 | } 55 | 56 | type envoyLogger struct { 57 | tag string 58 | native NativeLogger 59 | } 60 | 61 | func (l envoyLogger) Trace(message string, data ...interface{}) { 62 | l.log(loglevel.Trace, l.tag, message, data...) 63 | } 64 | 65 | func (l envoyLogger) Debug(message string, data ...interface{}) { 66 | l.log(loglevel.Debug, l.tag, message, data...) 67 | } 68 | 69 | func (l envoyLogger) Info(message string, data ...interface{}) { 70 | l.log(loglevel.Info, l.tag, message, data...) 71 | } 72 | 73 | func (l envoyLogger) Warn(message string, data ...interface{}) { 74 | l.log(loglevel.Warn, l.tag, message, data...) 75 | } 76 | 77 | func (l envoyLogger) Error(message string, data ...interface{}) { 78 | l.log(loglevel.Error, l.tag, message, data...) 79 | } 80 | 81 | func (l envoyLogger) Critical(message string, data ...interface{}) { 82 | l.log(loglevel.Critical, l.tag, message, data...) 83 | } 84 | 85 | // Log is a wrapper for suggesting developers use it with log.Data 86 | func (l envoyLogger) log(level loglevel.Type, tag, message string, data ...interface{}) { 87 | l.native.Log(level, tag, Render(message, data...)) 88 | } 89 | 90 | // NativeLogger is an interface to C Logger 91 | type NativeLogger interface { 92 | Log(level loglevel.Type, tag, message string) 93 | } 94 | -------------------------------------------------------------------------------- /ego/src/go/registry.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package ego 7 | 8 | import ( 9 | "github.com/grab/ego/ego/src/go/envoy" 10 | "github.com/grab/ego/ego/src/go/volatile" 11 | ) 12 | 13 | type HttpFilterFactoryFactory interface { 14 | CreateFilterFactory(config envoy.GoHttpFilterConfig) (HttpFilterFactory, error) 15 | CreateRouteSpecificFilterConfig(config envoy.GoHttpFilterConfig) (interface{}, error) 16 | } 17 | 18 | var httpFilterFactoryFactories = map[string]HttpFilterFactoryFactory{} 19 | 20 | func RegisterHttpFilter(name string, factory HttpFilterFactoryFactory) HttpFilterFactoryFactory { 21 | if _, found := httpFilterFactoryFactories[name]; found { 22 | // TODO: log error, make some noise 23 | } 24 | httpFilterFactoryFactories[name] = factory 25 | return factory 26 | } 27 | 28 | func GetHttpFilterFactoryFactory(name volatile.String) HttpFilterFactoryFactory { 29 | return httpFilterFactoryFactories[string(name)] 30 | } 31 | -------------------------------------------------------------------------------- /ego/src/go/volatile/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | # 3 | # Use of this source code is governed by the Apache License 2.0 that can be 4 | # found in the LICENSE file 5 | 6 | load("@io_bazel_rules_go//go:def.bzl", "go_library") 7 | 8 | go_library( 9 | name = "go_default_library", 10 | srcs = ["volatile.go"], 11 | cgo = True, 12 | importpath = "github.com/grab/ego/ego/src/go/volatile", 13 | visibility = ["//visibility:public"], 14 | ) 15 | -------------------------------------------------------------------------------- /ego/src/go/volatile/volatile.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package volatile 7 | 8 | import "C" 9 | import ( 10 | "reflect" 11 | "unsafe" 12 | ) 13 | 14 | // String should not be kept anywhere beyond the life cycle of the C callback. 15 | // In order to secure its contents, use String.Copy() 16 | type String string 17 | 18 | // Bytes should not be kept anywhere beyond the life cycle of the C callback. 19 | // In order to secure its contents, use Bytes.Copy() 20 | type Bytes []byte 21 | 22 | // Copy creates a non-volatile, "safe" copy of the volatile string 23 | func (s String) Copy() string { 24 | h := (*reflect.StringHeader)(unsafe.Pointer(&s)) 25 | return C.GoStringN((*C.char)(unsafe.Pointer(h.Data)), C.int(h.Len)) 26 | } 27 | 28 | // Copy creates a non-volatile, "safe" copy of the volatile buffer 29 | func (b Bytes) Copy() []byte { 30 | h := (*reflect.SliceHeader)(unsafe.Pointer(&b)) 31 | return C.GoBytes(unsafe.Pointer(h.Data), C.int(h.Cap))[:h.Len] 32 | } 33 | -------------------------------------------------------------------------------- /ego/test/cc/filter/http/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | # 3 | # Use of this source code is governed by the Apache License 2.0 that can be 4 | # found in the LICENSE file 5 | 6 | package(default_visibility = ["//visibility:public"]) 7 | 8 | load( 9 | "@envoy//bazel:envoy_build_system.bzl", 10 | "envoy_cc_mock", 11 | ) 12 | 13 | load( 14 | ":linkopts.bzl", 15 | "ego_cc_test", 16 | ) 17 | 18 | ego_cc_test( 19 | name = "http_filter_test", 20 | srcs = [ 21 | "filter_test.cc", 22 | "span-group_test.cc", 23 | ], 24 | repository = "@envoy", 25 | deps = [ 26 | ":cgo_proxy_mocks", 27 | "//ego/src/cc/filter/http:cgo", 28 | "//ego/src/cc/filter/http:factory", 29 | "//ego/src/cc/filter/http:native", 30 | "//egofilters/http/getheader/proto:pkg_cc_proto", 31 | "//egofilters/http/security/proto:pkg_cc_proto", 32 | "@envoy//test/mocks/http:http_mocks", 33 | ], 34 | ) 35 | 36 | envoy_cc_mock( 37 | name = "cgo_proxy_mocks", 38 | hdrs = ["mocks.h"], 39 | repository = "@envoy", 40 | ) 41 | -------------------------------------------------------------------------------- /ego/test/cc/filter/http/mocks.h: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | #include "gmock/gmock.h" // Brings in gMock. 7 | 8 | namespace Envoy { 9 | namespace Http { 10 | 11 | class MockCgoProxy : public CgoProxy { 12 | public: 13 | MockCgoProxy() = default; 14 | ~MockCgoProxy() override = default; 15 | 16 | MOCK_METHOD(unsigned long long, GoHttpFilterCreate, 17 | (void* native, unsigned long long factory_tag, unsigned long long filterSlot), 18 | (override)); 19 | MOCK_METHOD(void, GoHttpFilterOnDestroy, (unsigned long long filter_tag), (override)); 20 | MOCK_METHOD(long long, GoHttpFilterDecodeHeaders, 21 | (unsigned long long filter_tag, void* headers, int end_stream), (override)); 22 | MOCK_METHOD(long long, GoHttpFilterDecodeData, 23 | (unsigned long long filter_tag, void* buffer, int end_stream), (override)); 24 | MOCK_METHOD(long long, GoHttpFilterDecodeTrailers, 25 | (unsigned long long filter_tag, void* trailers), (override)); 26 | MOCK_METHOD(long long, GoHttpFilterEncodeHeaders, 27 | (unsigned long long filter_tag, void* headers, int end_stream), (override)); 28 | MOCK_METHOD(long long, GoHttpFilterEncodeData, 29 | (unsigned long long filter_tag, void* headers, int end_stream), (override)); 30 | MOCK_METHOD(void, GoHttpFilterOnPost, 31 | (unsigned long long filter_tag, unsigned long long post_tag), (override)); 32 | }; 33 | 34 | } // namespace Http 35 | } // namespace Envoy -------------------------------------------------------------------------------- /ego/test/cc/goc/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | # 3 | # Use of this source code is governed by the Apache License 2.0 that can be 4 | # found in the LICENSE file 5 | 6 | package(default_visibility = ["//visibility:public"]) 7 | 8 | load( 9 | "@envoy//bazel:envoy_build_system.bzl", 10 | "envoy_cc_test", 11 | ) 12 | 13 | envoy_cc_test( 14 | name = "goc_test", 15 | srcs = [ 16 | "requestheadermap_test.cc", 17 | ], 18 | repository = "@envoy", 19 | deps = [ 20 | "//ego/src/cc/goc:goc", 21 | "@envoy//test/test_common:utility_lib", 22 | ], 23 | ) 24 | -------------------------------------------------------------------------------- /ego/test/cc/goc/requestheadermap_test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | #include "test/test_common/utility.h" 7 | 8 | #include "ego/src/cc/filter/http/filter.h" 9 | #include "ego/src/cc/goc/envoy.h" 10 | #include "ego/src/cc/goc/proto/dto.pb.validate.h" 11 | 12 | class RequestHeaderMapGetByPrefixTest : public testing::Test { 13 | public: 14 | void init(char* prefix, char* buffer, size_t buffer_size) { 15 | EXPECT_EQ(strlen(prefix), 5); 16 | prefix_.len = strlen(prefix); 17 | prefix_.data = prefix; 18 | 19 | buffer_.data = buffer; 20 | buffer_.len = buffer_size; 21 | buffer_.cap = buffer_size; 22 | } 23 | 24 | GoBuf buffer_; 25 | GoStr prefix_; 26 | }; 27 | 28 | TEST_F(RequestHeaderMapGetByPrefixTest, FoundHeaders) { 29 | Envoy::Http::TestRequestHeaderMapImpl request_headers{{"x-ego1", "val1"}, {"x-ego2", "val2"}}; 30 | 31 | char c_buffer[100]; 32 | char c_prefix[] = "x-ego"; 33 | init(c_prefix, c_buffer, 100); 34 | 35 | auto size = RequestHeaderMap_getByPrefix(&request_headers, prefix_, buffer_); 36 | EXPECT_LT(0, size); 37 | 38 | auto result = ego::http::RequestHeaderMap{}; 39 | auto ok = result.ParseFromArray(buffer_.data, size); 40 | ASSERT_TRUE(ok); 41 | 42 | auto expected_result = ego::http::RequestHeaderMap{}; 43 | 44 | auto x_ego1_header = expected_result.add_headers(); 45 | x_ego1_header->set_key("x-ego1"); 46 | x_ego1_header->set_value("val1"); 47 | 48 | auto x_ego2_header = expected_result.add_headers(); 49 | x_ego2_header->set_key("x-ego2"); 50 | x_ego2_header->set_value("val2"); 51 | 52 | ASSERT_EQ(expected_result.SerializePartialAsString(), result.SerializePartialAsString()); 53 | } 54 | 55 | TEST_F(RequestHeaderMapGetByPrefixTest, NotFoundHeaders) { 56 | Envoy::Http::TestRequestHeaderMapImpl request_headers{}; 57 | 58 | char c_buffer[100]; 59 | char c_prefix[] = "x-ego"; 60 | init(c_prefix, c_buffer, 100); 61 | 62 | auto size = RequestHeaderMap_getByPrefix(&request_headers, prefix_, buffer_); 63 | EXPECT_EQ(0, size); 64 | } 65 | 66 | TEST_F(RequestHeaderMapGetByPrefixTest, ShouldNotWriteOverBufferSize) { 67 | Envoy::Http::TestRequestHeaderMapImpl request_headers{{"x-ego1", "val1"}, {"x-ego2", "val2"}}; 68 | 69 | const auto buffer_size = 34; 70 | char c_buffer[] = "0123456789012345678901234567890123should_not_be_overriden"; 71 | 72 | char c_prefix[] = "x-ego"; 73 | init(c_prefix, c_buffer, buffer_size); 74 | 75 | auto size = RequestHeaderMap_getByPrefix(&request_headers, prefix_, buffer_); 76 | EXPECT_EQ(32, size); 77 | 78 | // getByPrefix should not write over the buffer size 79 | char expected_buffer[] = "0123456789012345678901234567890123should_not_be_overriden"; 80 | ASSERT_STREQ(expected_buffer + buffer_size, c_buffer + buffer_size); 81 | } 82 | 83 | TEST_F(RequestHeaderMapGetByPrefixTest, TooSmallBuffer) { 84 | Envoy::Http::TestRequestHeaderMapImpl request_headers{{"x-ego1", "val1"}, {"x-ego2", "val2"}}; 85 | 86 | const auto buffer_size = 10; 87 | char c_buffer[] = "this is a buffer with existing data"; 88 | 89 | char c_prefix[] = "x-ego"; 90 | init(c_prefix, c_buffer, buffer_size); 91 | 92 | auto size = RequestHeaderMap_getByPrefix(&request_headers, prefix_, buffer_); 93 | EXPECT_GT(size, buffer_size); 94 | 95 | // getByPrefix should not write to buffer size 96 | char expected_buffer[] = "this is a buffer with existing data"; 97 | ASSERT_STREQ(expected_buffer, c_buffer); 98 | } -------------------------------------------------------------------------------- /ego/test/go/mock/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | # 3 | # Use of this source code is governed by the Apache License 2.0 that can be 4 | # found in the LICENSE file 5 | 6 | load("@io_bazel_rules_go//go:def.bzl", "go_library") 7 | 8 | go_library( 9 | name = "go_default_library", 10 | srcs = [ 11 | "doc.go", 12 | "envoy.go", 13 | "logger.go", 14 | ], 15 | importpath = "github.com/grab/ego/ego/test/go/mock", 16 | visibility = ["//visibility:public"], 17 | deps = [ 18 | "//ego/src/go/envoy:go_default_library", 19 | "//ego/src/go/envoy/loglevel:go_default_library", 20 | "//ego/src/go/volatile:go_default_library", 21 | ], 22 | ) 23 | -------------------------------------------------------------------------------- /ego/test/go/mock/doc.go: -------------------------------------------------------------------------------- 1 | package mock 2 | 3 | //go:generate mockery --all --recursive=true --keeptree --case=underscore --output ./gen/envoy --dir ../../../src/go/envoy 4 | -------------------------------------------------------------------------------- /ego/test/go/mock/envoy.go: -------------------------------------------------------------------------------- 1 | package mock 2 | 3 | import ( 4 | "github.com/grab/ego/ego/src/go/envoy" 5 | "github.com/grab/ego/ego/src/go/volatile" 6 | ) 7 | 8 | type GoHttpFilterConfig struct { 9 | ConfigBytes []byte 10 | EnvoyScope envoy.Scope 11 | } 12 | 13 | func (conf *GoHttpFilterConfig) Settings() volatile.Bytes { 14 | return volatile.Bytes(conf.ConfigBytes) 15 | } 16 | 17 | func (conf *GoHttpFilterConfig) Scope() envoy.Scope { 18 | return conf.EnvoyScope 19 | } 20 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "go_default_library", 5 | srcs = [ 6 | "buffer_instance.go", 7 | "counter.go", 8 | "decoder_filter_callbacks.go", 9 | "encoder_filter_callbacks.go", 10 | "filter_state.go", 11 | "gauge.go", 12 | "generic_secret_config_provider.go", 13 | "go_http_filter.go", 14 | "go_http_filter_config.go", 15 | "header_map.go", 16 | "header_map_read_only.go", 17 | "header_map_updatable.go", 18 | "histogram.go", 19 | "path_match_criterion.go", 20 | "request_header_map.go", 21 | "request_header_map_read_only.go", 22 | "request_header_map_updatable.go", 23 | "request_or_response_header_map.go", 24 | "request_or_response_header_map_read_only.go", 25 | "request_or_response_header_map_updatable.go", 26 | "request_trailer_map.go", 27 | "request_trailer_map_read_only.go", 28 | "request_trailer_map_updatable.go", 29 | "response_header_map.go", 30 | "response_header_map_read_only.go", 31 | "response_header_map_updatable.go", 32 | "route.go", 33 | "route_entry.go", 34 | "scope.go", 35 | "span.go", 36 | "stream_filter_callbacks.go", 37 | "stream_info.go", 38 | ], 39 | importpath = "github.com/grab/ego/ego/test/go/mock/gen/envoy", 40 | visibility = ["//visibility:public"], 41 | deps = [ 42 | "//ego/src/cc/goc/proto:go_default_library", 43 | "//ego/src/go/envoy:go_default_library", 44 | "//ego/src/go/envoy/lifespan:go_default_library", 45 | "//ego/src/go/envoy/loglevel:go_default_library", 46 | "//ego/src/go/envoy/statetype:go_default_library", 47 | "//ego/src/go/envoy/stats:go_default_library", 48 | "//ego/src/go/volatile:go_default_library", 49 | "@com_github_stretchr_testify//mock:go_default_library", 50 | ], 51 | ) 52 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/buffer_instance.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | io "io" 7 | 8 | volatile "github.com/grab/ego/ego/src/go/volatile" 9 | mock "github.com/stretchr/testify/mock" 10 | ) 11 | 12 | // BufferInstance is an autogenerated mock type for the BufferInstance type 13 | type BufferInstance struct { 14 | mock.Mock 15 | } 16 | 17 | // CopyOut provides a mock function with given fields: start, p 18 | func (_m *BufferInstance) CopyOut(start uint64, p []byte) int { 19 | ret := _m.Called(start, p) 20 | 21 | var r0 int 22 | if rf, ok := ret.Get(0).(func(uint64, []byte) int); ok { 23 | r0 = rf(start, p) 24 | } else { 25 | r0 = ret.Get(0).(int) 26 | } 27 | 28 | return r0 29 | } 30 | 31 | // GetRawSlices provides a mock function with given fields: 32 | func (_m *BufferInstance) GetRawSlices() []volatile.Bytes { 33 | ret := _m.Called() 34 | 35 | var r0 []volatile.Bytes 36 | if rf, ok := ret.Get(0).(func() []volatile.Bytes); ok { 37 | r0 = rf() 38 | } else { 39 | if ret.Get(0) != nil { 40 | r0 = ret.Get(0).([]volatile.Bytes) 41 | } 42 | } 43 | 44 | return r0 45 | } 46 | 47 | // Length provides a mock function with given fields: 48 | func (_m *BufferInstance) Length() uint64 { 49 | ret := _m.Called() 50 | 51 | var r0 uint64 52 | if rf, ok := ret.Get(0).(func() uint64); ok { 53 | r0 = rf() 54 | } else { 55 | r0 = ret.Get(0).(uint64) 56 | } 57 | 58 | return r0 59 | } 60 | 61 | // NewReader provides a mock function with given fields: start 62 | func (_m *BufferInstance) NewReader(start uint64) io.Reader { 63 | ret := _m.Called(start) 64 | 65 | var r0 io.Reader 66 | if rf, ok := ret.Get(0).(func(uint64) io.Reader); ok { 67 | r0 = rf(start) 68 | } else { 69 | if ret.Get(0) != nil { 70 | r0 = ret.Get(0).(io.Reader) 71 | } 72 | } 73 | 74 | return r0 75 | } 76 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/counter.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import mock "github.com/stretchr/testify/mock" 6 | 7 | // Counter is an autogenerated mock type for the Counter type 8 | type Counter struct { 9 | mock.Mock 10 | } 11 | 12 | // Add provides a mock function with given fields: amount 13 | func (_m *Counter) Add(amount uint64) { 14 | _m.Called(amount) 15 | } 16 | 17 | // Inc provides a mock function with given fields: 18 | func (_m *Counter) Inc() { 19 | _m.Called() 20 | } 21 | 22 | // Latch provides a mock function with given fields: 23 | func (_m *Counter) Latch() uint64 { 24 | ret := _m.Called() 25 | 26 | var r0 uint64 27 | if rf, ok := ret.Get(0).(func() uint64); ok { 28 | r0 = rf() 29 | } else { 30 | r0 = ret.Get(0).(uint64) 31 | } 32 | 33 | return r0 34 | } 35 | 36 | // Reset provides a mock function with given fields: 37 | func (_m *Counter) Reset() { 38 | _m.Called() 39 | } 40 | 41 | // Value provides a mock function with given fields: 42 | func (_m *Counter) Value() uint64 { 43 | ret := _m.Called() 44 | 45 | var r0 uint64 46 | if rf, ok := ret.Get(0).(func() uint64); ok { 47 | r0 = rf() 48 | } else { 49 | r0 = ret.Get(0).(uint64) 50 | } 51 | 52 | return r0 53 | } 54 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/decoder_filter_callbacks.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | ego_http "github.com/grab/ego/ego/src/cc/goc/proto" 7 | envoy "github.com/grab/ego/ego/src/go/envoy" 8 | 9 | mock "github.com/stretchr/testify/mock" 10 | ) 11 | 12 | // DecoderFilterCallbacks is an autogenerated mock type for the DecoderFilterCallbacks type 13 | type DecoderFilterCallbacks struct { 14 | mock.Mock 15 | } 16 | 17 | // ActiveSpan provides a mock function with given fields: 18 | func (_m *DecoderFilterCallbacks) ActiveSpan() envoy.Span { 19 | ret := _m.Called() 20 | 21 | var r0 envoy.Span 22 | if rf, ok := ret.Get(0).(func() envoy.Span); ok { 23 | r0 = rf() 24 | } else { 25 | if ret.Get(0) != nil { 26 | r0 = ret.Get(0).(envoy.Span) 27 | } 28 | } 29 | 30 | return r0 31 | } 32 | 33 | // AddDecodedData provides a mock function with given fields: buffer, streamingFilter 34 | func (_m *DecoderFilterCallbacks) AddDecodedData(buffer envoy.BufferInstance, streamingFilter bool) { 35 | _m.Called(buffer, streamingFilter) 36 | } 37 | 38 | // ContinueDecoding provides a mock function with given fields: 39 | func (_m *DecoderFilterCallbacks) ContinueDecoding() { 40 | _m.Called() 41 | } 42 | 43 | // DecodingBuffer provides a mock function with given fields: 44 | func (_m *DecoderFilterCallbacks) DecodingBuffer() envoy.BufferInstance { 45 | ret := _m.Called() 46 | 47 | var r0 envoy.BufferInstance 48 | if rf, ok := ret.Get(0).(func() envoy.BufferInstance); ok { 49 | r0 = rf() 50 | } else { 51 | if ret.Get(0) != nil { 52 | r0 = ret.Get(0).(envoy.BufferInstance) 53 | } 54 | } 55 | 56 | return r0 57 | } 58 | 59 | // EncodeHeaders provides a mock function with given fields: responseCode, headers, endStream 60 | func (_m *DecoderFilterCallbacks) EncodeHeaders(responseCode int, headers *ego_http.ResponseHeaderMap, endStream bool) { 61 | _m.Called(responseCode, headers, endStream) 62 | } 63 | 64 | // Route provides a mock function with given fields: 65 | func (_m *DecoderFilterCallbacks) Route() envoy.Route { 66 | ret := _m.Called() 67 | 68 | var r0 envoy.Route 69 | if rf, ok := ret.Get(0).(func() envoy.Route); ok { 70 | r0 = rf() 71 | } else { 72 | if ret.Get(0) != nil { 73 | r0 = ret.Get(0).(envoy.Route) 74 | } 75 | } 76 | 77 | return r0 78 | } 79 | 80 | // RouteExisting provides a mock function with given fields: 81 | func (_m *DecoderFilterCallbacks) RouteExisting() bool { 82 | ret := _m.Called() 83 | 84 | var r0 bool 85 | if rf, ok := ret.Get(0).(func() bool); ok { 86 | r0 = rf() 87 | } else { 88 | r0 = ret.Get(0).(bool) 89 | } 90 | 91 | return r0 92 | } 93 | 94 | // SendLocalReply provides a mock function with given fields: responseCode, body, headers, details 95 | func (_m *DecoderFilterCallbacks) SendLocalReply(responseCode int, body string, headers map[string]string, details string) { 96 | _m.Called(responseCode, body, headers, details) 97 | } 98 | 99 | // StreamInfo provides a mock function with given fields: 100 | func (_m *DecoderFilterCallbacks) StreamInfo() envoy.StreamInfo { 101 | ret := _m.Called() 102 | 103 | var r0 envoy.StreamInfo 104 | if rf, ok := ret.Get(0).(func() envoy.StreamInfo); ok { 105 | r0 = rf() 106 | } else { 107 | if ret.Get(0) != nil { 108 | r0 = ret.Get(0).(envoy.StreamInfo) 109 | } 110 | } 111 | 112 | return r0 113 | } 114 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/encoder_filter_callbacks.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | envoy "github.com/grab/ego/ego/src/go/envoy" 7 | mock "github.com/stretchr/testify/mock" 8 | ) 9 | 10 | // EncoderFilterCallbacks is an autogenerated mock type for the EncoderFilterCallbacks type 11 | type EncoderFilterCallbacks struct { 12 | mock.Mock 13 | } 14 | 15 | // ActiveSpan provides a mock function with given fields: 16 | func (_m *EncoderFilterCallbacks) ActiveSpan() envoy.Span { 17 | ret := _m.Called() 18 | 19 | var r0 envoy.Span 20 | if rf, ok := ret.Get(0).(func() envoy.Span); ok { 21 | r0 = rf() 22 | } else { 23 | if ret.Get(0) != nil { 24 | r0 = ret.Get(0).(envoy.Span) 25 | } 26 | } 27 | 28 | return r0 29 | } 30 | 31 | // AddEncodedData provides a mock function with given fields: buffer, streamingFilter 32 | func (_m *EncoderFilterCallbacks) AddEncodedData(buffer envoy.BufferInstance, streamingFilter bool) { 33 | _m.Called(buffer, streamingFilter) 34 | } 35 | 36 | // ContinueEncoding provides a mock function with given fields: 37 | func (_m *EncoderFilterCallbacks) ContinueEncoding() { 38 | _m.Called() 39 | } 40 | 41 | // EncodingBuffer provides a mock function with given fields: 42 | func (_m *EncoderFilterCallbacks) EncodingBuffer() envoy.BufferInstance { 43 | ret := _m.Called() 44 | 45 | var r0 envoy.BufferInstance 46 | if rf, ok := ret.Get(0).(func() envoy.BufferInstance); ok { 47 | r0 = rf() 48 | } else { 49 | if ret.Get(0) != nil { 50 | r0 = ret.Get(0).(envoy.BufferInstance) 51 | } 52 | } 53 | 54 | return r0 55 | } 56 | 57 | // Route provides a mock function with given fields: 58 | func (_m *EncoderFilterCallbacks) Route() envoy.Route { 59 | ret := _m.Called() 60 | 61 | var r0 envoy.Route 62 | if rf, ok := ret.Get(0).(func() envoy.Route); ok { 63 | r0 = rf() 64 | } else { 65 | if ret.Get(0) != nil { 66 | r0 = ret.Get(0).(envoy.Route) 67 | } 68 | } 69 | 70 | return r0 71 | } 72 | 73 | // RouteExisting provides a mock function with given fields: 74 | func (_m *EncoderFilterCallbacks) RouteExisting() bool { 75 | ret := _m.Called() 76 | 77 | var r0 bool 78 | if rf, ok := ret.Get(0).(func() bool); ok { 79 | r0 = rf() 80 | } else { 81 | r0 = ret.Get(0).(bool) 82 | } 83 | 84 | return r0 85 | } 86 | 87 | // StreamInfo provides a mock function with given fields: 88 | func (_m *EncoderFilterCallbacks) StreamInfo() envoy.StreamInfo { 89 | ret := _m.Called() 90 | 91 | var r0 envoy.StreamInfo 92 | if rf, ok := ret.Get(0).(func() envoy.StreamInfo); ok { 93 | r0 = rf() 94 | } else { 95 | if ret.Get(0) != nil { 96 | r0 = ret.Get(0).(envoy.StreamInfo) 97 | } 98 | } 99 | 100 | return r0 101 | } 102 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/filter_state.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | lifespan "github.com/grab/ego/ego/src/go/envoy/lifespan" 7 | mock "github.com/stretchr/testify/mock" 8 | 9 | statetype "github.com/grab/ego/ego/src/go/envoy/statetype" 10 | 11 | volatile "github.com/grab/ego/ego/src/go/volatile" 12 | ) 13 | 14 | // FilterState is an autogenerated mock type for the FilterState type 15 | type FilterState struct { 16 | mock.Mock 17 | } 18 | 19 | // GetDataReadOnly provides a mock function with given fields: name 20 | func (_m *FilterState) GetDataReadOnly(name string) (volatile.String, bool) { 21 | ret := _m.Called(name) 22 | 23 | var r0 volatile.String 24 | if rf, ok := ret.Get(0).(func(string) volatile.String); ok { 25 | r0 = rf(name) 26 | } else { 27 | r0 = ret.Get(0).(volatile.String) 28 | } 29 | 30 | var r1 bool 31 | if rf, ok := ret.Get(1).(func(string) bool); ok { 32 | r1 = rf(name) 33 | } else { 34 | r1 = ret.Get(1).(bool) 35 | } 36 | 37 | return r0, r1 38 | } 39 | 40 | // SetData provides a mock function with given fields: name, value, stateType, lifeSpan 41 | func (_m *FilterState) SetData(name string, value string, stateType statetype.Type, lifeSpan lifespan.Type) { 42 | _m.Called(name, value, stateType, lifeSpan) 43 | } 44 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/gauge.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import mock "github.com/stretchr/testify/mock" 6 | 7 | // Gauge is an autogenerated mock type for the Gauge type 8 | type Gauge struct { 9 | mock.Mock 10 | } 11 | 12 | // Add provides a mock function with given fields: amount 13 | func (_m *Gauge) Add(amount uint64) { 14 | _m.Called(amount) 15 | } 16 | 17 | // Dec provides a mock function with given fields: 18 | func (_m *Gauge) Dec() { 19 | _m.Called() 20 | } 21 | 22 | // Inc provides a mock function with given fields: 23 | func (_m *Gauge) Inc() { 24 | _m.Called() 25 | } 26 | 27 | // Set provides a mock function with given fields: value 28 | func (_m *Gauge) Set(value uint64) { 29 | _m.Called(value) 30 | } 31 | 32 | // Sub provides a mock function with given fields: amount 33 | func (_m *Gauge) Sub(amount uint64) { 34 | _m.Called(amount) 35 | } 36 | 37 | // Value provides a mock function with given fields: 38 | func (_m *Gauge) Value() uint64 { 39 | ret := _m.Called() 40 | 41 | var r0 uint64 42 | if rf, ok := ret.Get(0).(func() uint64); ok { 43 | r0 = rf() 44 | } else { 45 | r0 = ret.Get(0).(uint64) 46 | } 47 | 48 | return r0 49 | } 50 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/generic_secret_config_provider.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | volatile "github.com/grab/ego/ego/src/go/volatile" 7 | mock "github.com/stretchr/testify/mock" 8 | ) 9 | 10 | // GenericSecretConfigProvider is an autogenerated mock type for the GenericSecretConfigProvider type 11 | type GenericSecretConfigProvider struct { 12 | mock.Mock 13 | } 14 | 15 | // Secret provides a mock function with given fields: 16 | func (_m *GenericSecretConfigProvider) Secret() volatile.String { 17 | ret := _m.Called() 18 | 19 | var r0 volatile.String 20 | if rf, ok := ret.Get(0).(func() volatile.String); ok { 21 | r0 = rf() 22 | } else { 23 | r0 = ret.Get(0).(volatile.String) 24 | } 25 | 26 | return r0 27 | } 28 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/go_http_filter.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | envoy "github.com/grab/ego/ego/src/go/envoy" 7 | loglevel "github.com/grab/ego/ego/src/go/envoy/loglevel" 8 | 9 | mock "github.com/stretchr/testify/mock" 10 | ) 11 | 12 | // GoHttpFilter is an autogenerated mock type for the GoHttpFilter type 13 | type GoHttpFilter struct { 14 | mock.Mock 15 | } 16 | 17 | // DecoderCallbacks provides a mock function with given fields: 18 | func (_m *GoHttpFilter) DecoderCallbacks() envoy.DecoderFilterCallbacks { 19 | ret := _m.Called() 20 | 21 | var r0 envoy.DecoderFilterCallbacks 22 | if rf, ok := ret.Get(0).(func() envoy.DecoderFilterCallbacks); ok { 23 | r0 = rf() 24 | } else { 25 | if ret.Get(0) != nil { 26 | r0 = ret.Get(0).(envoy.DecoderFilterCallbacks) 27 | } 28 | } 29 | 30 | return r0 31 | } 32 | 33 | // EncoderCallbacks provides a mock function with given fields: 34 | func (_m *GoHttpFilter) EncoderCallbacks() envoy.EncoderFilterCallbacks { 35 | ret := _m.Called() 36 | 37 | var r0 envoy.EncoderFilterCallbacks 38 | if rf, ok := ret.Get(0).(func() envoy.EncoderFilterCallbacks); ok { 39 | r0 = rf() 40 | } else { 41 | if ret.Get(0) != nil { 42 | r0 = ret.Get(0).(envoy.EncoderFilterCallbacks) 43 | } 44 | } 45 | 46 | return r0 47 | } 48 | 49 | // GenericSecretProvider provides a mock function with given fields: 50 | func (_m *GoHttpFilter) GenericSecretProvider() envoy.GenericSecretConfigProvider { 51 | ret := _m.Called() 52 | 53 | var r0 envoy.GenericSecretConfigProvider 54 | if rf, ok := ret.Get(0).(func() envoy.GenericSecretConfigProvider); ok { 55 | r0 = rf() 56 | } else { 57 | if ret.Get(0) != nil { 58 | r0 = ret.Get(0).(envoy.GenericSecretConfigProvider) 59 | } 60 | } 61 | 62 | return r0 63 | } 64 | 65 | // Log provides a mock function with given fields: _a0, _a1 66 | func (_m *GoHttpFilter) Log(_a0 loglevel.Type, _a1 string) { 67 | _m.Called(_a0, _a1) 68 | } 69 | 70 | // Pin provides a mock function with given fields: 71 | func (_m *GoHttpFilter) Pin() { 72 | _m.Called() 73 | } 74 | 75 | // Post provides a mock function with given fields: _a0 76 | func (_m *GoHttpFilter) Post(_a0 uint64) { 77 | _m.Called(_a0) 78 | } 79 | 80 | // ResolveMostSpecificPerGoFilterConfig provides a mock function with given fields: name, route 81 | func (_m *GoHttpFilter) ResolveMostSpecificPerGoFilterConfig(name string, route envoy.Route) interface{} { 82 | ret := _m.Called(name, route) 83 | 84 | var r0 interface{} 85 | if rf, ok := ret.Get(0).(func(string, envoy.Route) interface{}); ok { 86 | r0 = rf(name, route) 87 | } else { 88 | if ret.Get(0) != nil { 89 | r0 = ret.Get(0).(interface{}) 90 | } 91 | } 92 | 93 | return r0 94 | } 95 | 96 | // Unpin provides a mock function with given fields: 97 | func (_m *GoHttpFilter) Unpin() { 98 | _m.Called() 99 | } 100 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/go_http_filter_config.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | envoy "github.com/grab/ego/ego/src/go/envoy" 7 | mock "github.com/stretchr/testify/mock" 8 | 9 | volatile "github.com/grab/ego/ego/src/go/volatile" 10 | ) 11 | 12 | // GoHttpFilterConfig is an autogenerated mock type for the GoHttpFilterConfig type 13 | type GoHttpFilterConfig struct { 14 | mock.Mock 15 | } 16 | 17 | // Scope provides a mock function with given fields: 18 | func (_m *GoHttpFilterConfig) Scope() envoy.Scope { 19 | ret := _m.Called() 20 | 21 | var r0 envoy.Scope 22 | if rf, ok := ret.Get(0).(func() envoy.Scope); ok { 23 | r0 = rf() 24 | } else { 25 | if ret.Get(0) != nil { 26 | r0 = ret.Get(0).(envoy.Scope) 27 | } 28 | } 29 | 30 | return r0 31 | } 32 | 33 | // Settings provides a mock function with given fields: 34 | func (_m *GoHttpFilterConfig) Settings() volatile.Bytes { 35 | ret := _m.Called() 36 | 37 | var r0 volatile.Bytes 38 | if rf, ok := ret.Get(0).(func() volatile.Bytes); ok { 39 | r0 = rf() 40 | } else { 41 | if ret.Get(0) != nil { 42 | r0 = ret.Get(0).(volatile.Bytes) 43 | } 44 | } 45 | 46 | return r0 47 | } 48 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/header_map.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | volatile "github.com/grab/ego/ego/src/go/volatile" 7 | mock "github.com/stretchr/testify/mock" 8 | ) 9 | 10 | // HeaderMap is an autogenerated mock type for the HeaderMap type 11 | type HeaderMap struct { 12 | mock.Mock 13 | } 14 | 15 | // AddCopy provides a mock function with given fields: name, value 16 | func (_m *HeaderMap) AddCopy(name string, value string) { 17 | _m.Called(name, value) 18 | } 19 | 20 | // AppendCopy provides a mock function with given fields: name, value 21 | func (_m *HeaderMap) AppendCopy(name string, value string) { 22 | _m.Called(name, value) 23 | } 24 | 25 | // Get provides a mock function with given fields: name 26 | func (_m *HeaderMap) Get(name string) volatile.String { 27 | ret := _m.Called(name) 28 | 29 | var r0 volatile.String 30 | if rf, ok := ret.Get(0).(func(string) volatile.String); ok { 31 | r0 = rf(name) 32 | } else { 33 | r0 = ret.Get(0).(volatile.String) 34 | } 35 | 36 | return r0 37 | } 38 | 39 | // Remove provides a mock function with given fields: name 40 | func (_m *HeaderMap) Remove(name string) { 41 | _m.Called(name) 42 | } 43 | 44 | // SetCopy provides a mock function with given fields: name, value 45 | func (_m *HeaderMap) SetCopy(name string, value string) { 46 | _m.Called(name, value) 47 | } 48 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/header_map_read_only.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | volatile "github.com/grab/ego/ego/src/go/volatile" 7 | mock "github.com/stretchr/testify/mock" 8 | ) 9 | 10 | // HeaderMapReadOnly is an autogenerated mock type for the HeaderMapReadOnly type 11 | type HeaderMapReadOnly struct { 12 | mock.Mock 13 | } 14 | 15 | // Get provides a mock function with given fields: name 16 | func (_m *HeaderMapReadOnly) Get(name string) volatile.String { 17 | ret := _m.Called(name) 18 | 19 | var r0 volatile.String 20 | if rf, ok := ret.Get(0).(func(string) volatile.String); ok { 21 | r0 = rf(name) 22 | } else { 23 | r0 = ret.Get(0).(volatile.String) 24 | } 25 | 26 | return r0 27 | } 28 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/header_map_updatable.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import mock "github.com/stretchr/testify/mock" 6 | 7 | // headerMapUpdatable is an autogenerated mock type for the headerMapUpdatable type 8 | type headerMapUpdatable struct { 9 | mock.Mock 10 | } 11 | 12 | // AddCopy provides a mock function with given fields: name, value 13 | func (_m *headerMapUpdatable) AddCopy(name string, value string) { 14 | _m.Called(name, value) 15 | } 16 | 17 | // AppendCopy provides a mock function with given fields: name, value 18 | func (_m *headerMapUpdatable) AppendCopy(name string, value string) { 19 | _m.Called(name, value) 20 | } 21 | 22 | // Remove provides a mock function with given fields: name 23 | func (_m *headerMapUpdatable) Remove(name string) { 24 | _m.Called(name) 25 | } 26 | 27 | // SetCopy provides a mock function with given fields: name, value 28 | func (_m *headerMapUpdatable) SetCopy(name string, value string) { 29 | _m.Called(name, value) 30 | } 31 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/histogram.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | stats "github.com/grab/ego/ego/src/go/envoy/stats" 7 | mock "github.com/stretchr/testify/mock" 8 | ) 9 | 10 | // Histogram is an autogenerated mock type for the Histogram type 11 | type Histogram struct { 12 | mock.Mock 13 | } 14 | 15 | // RecordValue provides a mock function with given fields: value 16 | func (_m *Histogram) RecordValue(value uint64) { 17 | _m.Called(value) 18 | } 19 | 20 | // Unit provides a mock function with given fields: 21 | func (_m *Histogram) Unit() stats.Unit { 22 | ret := _m.Called() 23 | 24 | var r0 stats.Unit 25 | if rf, ok := ret.Get(0).(func() stats.Unit); ok { 26 | r0 = rf() 27 | } else { 28 | r0 = ret.Get(0).(stats.Unit) 29 | } 30 | 31 | return r0 32 | } 33 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/path_match_criterion.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | envoy "github.com/grab/ego/ego/src/go/envoy" 7 | mock "github.com/stretchr/testify/mock" 8 | 9 | volatile "github.com/grab/ego/ego/src/go/volatile" 10 | ) 11 | 12 | // PathMatchCriterion is an autogenerated mock type for the PathMatchCriterion type 13 | type PathMatchCriterion struct { 14 | mock.Mock 15 | } 16 | 17 | // MatchType provides a mock function with given fields: 18 | func (_m *PathMatchCriterion) MatchType() (envoy.PathMatchType, error) { 19 | ret := _m.Called() 20 | 21 | var r0 envoy.PathMatchType 22 | if rf, ok := ret.Get(0).(func() envoy.PathMatchType); ok { 23 | r0 = rf() 24 | } else { 25 | r0 = ret.Get(0).(envoy.PathMatchType) 26 | } 27 | 28 | var r1 error 29 | if rf, ok := ret.Get(1).(func() error); ok { 30 | r1 = rf() 31 | } else { 32 | r1 = ret.Error(1) 33 | } 34 | 35 | return r0, r1 36 | } 37 | 38 | // Matcher provides a mock function with given fields: 39 | func (_m *PathMatchCriterion) Matcher() (volatile.String, error) { 40 | ret := _m.Called() 41 | 42 | var r0 volatile.String 43 | if rf, ok := ret.Get(0).(func() volatile.String); ok { 44 | r0 = rf() 45 | } else { 46 | r0 = ret.Get(0).(volatile.String) 47 | } 48 | 49 | var r1 error 50 | if rf, ok := ret.Get(1).(func() error); ok { 51 | r1 = rf() 52 | } else { 53 | r1 = ret.Error(1) 54 | } 55 | 56 | return r0, r1 57 | } 58 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/request_header_map.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | volatile "github.com/grab/ego/ego/src/go/volatile" 7 | mock "github.com/stretchr/testify/mock" 8 | ) 9 | 10 | // RequestHeaderMap is an autogenerated mock type for the RequestHeaderMap type 11 | type RequestHeaderMap struct { 12 | mock.Mock 13 | } 14 | 15 | // AddCopy provides a mock function with given fields: name, value 16 | func (_m *RequestHeaderMap) AddCopy(name string, value string) { 17 | _m.Called(name, value) 18 | } 19 | 20 | // AppendCopy provides a mock function with given fields: name, value 21 | func (_m *RequestHeaderMap) AppendCopy(name string, value string) { 22 | _m.Called(name, value) 23 | } 24 | 25 | // Authorization provides a mock function with given fields: 26 | func (_m *RequestHeaderMap) Authorization() volatile.String { 27 | ret := _m.Called() 28 | 29 | var r0 volatile.String 30 | if rf, ok := ret.Get(0).(func() volatile.String); ok { 31 | r0 = rf() 32 | } else { 33 | r0 = ret.Get(0).(volatile.String) 34 | } 35 | 36 | return r0 37 | } 38 | 39 | // ContentType provides a mock function with given fields: 40 | func (_m *RequestHeaderMap) ContentType() volatile.String { 41 | ret := _m.Called() 42 | 43 | var r0 volatile.String 44 | if rf, ok := ret.Get(0).(func() volatile.String); ok { 45 | r0 = rf() 46 | } else { 47 | r0 = ret.Get(0).(volatile.String) 48 | } 49 | 50 | return r0 51 | } 52 | 53 | // Get provides a mock function with given fields: name 54 | func (_m *RequestHeaderMap) Get(name string) volatile.String { 55 | ret := _m.Called(name) 56 | 57 | var r0 volatile.String 58 | if rf, ok := ret.Get(0).(func(string) volatile.String); ok { 59 | r0 = rf(name) 60 | } else { 61 | r0 = ret.Get(0).(volatile.String) 62 | } 63 | 64 | return r0 65 | } 66 | 67 | // GetByPrefix provides a mock function with given fields: prefix 68 | func (_m *RequestHeaderMap) GetByPrefix(prefix string) map[string][]string { 69 | ret := _m.Called(prefix) 70 | 71 | var r0 map[string][]string 72 | if rf, ok := ret.Get(0).(func(string) map[string][]string); ok { 73 | r0 = rf(prefix) 74 | } else { 75 | if ret.Get(0) != nil { 76 | r0 = ret.Get(0).(map[string][]string) 77 | } 78 | } 79 | 80 | return r0 81 | } 82 | 83 | // Method provides a mock function with given fields: 84 | func (_m *RequestHeaderMap) Method() volatile.String { 85 | ret := _m.Called() 86 | 87 | var r0 volatile.String 88 | if rf, ok := ret.Get(0).(func() volatile.String); ok { 89 | r0 = rf() 90 | } else { 91 | r0 = ret.Get(0).(volatile.String) 92 | } 93 | 94 | return r0 95 | } 96 | 97 | // Path provides a mock function with given fields: 98 | func (_m *RequestHeaderMap) Path() volatile.String { 99 | ret := _m.Called() 100 | 101 | var r0 volatile.String 102 | if rf, ok := ret.Get(0).(func() volatile.String); ok { 103 | r0 = rf() 104 | } else { 105 | r0 = ret.Get(0).(volatile.String) 106 | } 107 | 108 | return r0 109 | } 110 | 111 | // Remove provides a mock function with given fields: name 112 | func (_m *RequestHeaderMap) Remove(name string) { 113 | _m.Called(name) 114 | } 115 | 116 | // SetCopy provides a mock function with given fields: name, value 117 | func (_m *RequestHeaderMap) SetCopy(name string, value string) { 118 | _m.Called(name, value) 119 | } 120 | 121 | // SetPath provides a mock function with given fields: path 122 | func (_m *RequestHeaderMap) SetPath(path string) { 123 | _m.Called(path) 124 | } 125 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/request_header_map_read_only.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | volatile "github.com/grab/ego/ego/src/go/volatile" 7 | mock "github.com/stretchr/testify/mock" 8 | ) 9 | 10 | // RequestHeaderMapReadOnly is an autogenerated mock type for the RequestHeaderMapReadOnly type 11 | type RequestHeaderMapReadOnly struct { 12 | mock.Mock 13 | } 14 | 15 | // Authorization provides a mock function with given fields: 16 | func (_m *RequestHeaderMapReadOnly) Authorization() volatile.String { 17 | ret := _m.Called() 18 | 19 | var r0 volatile.String 20 | if rf, ok := ret.Get(0).(func() volatile.String); ok { 21 | r0 = rf() 22 | } else { 23 | r0 = ret.Get(0).(volatile.String) 24 | } 25 | 26 | return r0 27 | } 28 | 29 | // ContentType provides a mock function with given fields: 30 | func (_m *RequestHeaderMapReadOnly) ContentType() volatile.String { 31 | ret := _m.Called() 32 | 33 | var r0 volatile.String 34 | if rf, ok := ret.Get(0).(func() volatile.String); ok { 35 | r0 = rf() 36 | } else { 37 | r0 = ret.Get(0).(volatile.String) 38 | } 39 | 40 | return r0 41 | } 42 | 43 | // Get provides a mock function with given fields: name 44 | func (_m *RequestHeaderMapReadOnly) Get(name string) volatile.String { 45 | ret := _m.Called(name) 46 | 47 | var r0 volatile.String 48 | if rf, ok := ret.Get(0).(func(string) volatile.String); ok { 49 | r0 = rf(name) 50 | } else { 51 | r0 = ret.Get(0).(volatile.String) 52 | } 53 | 54 | return r0 55 | } 56 | 57 | // GetByPrefix provides a mock function with given fields: prefix 58 | func (_m *RequestHeaderMapReadOnly) GetByPrefix(prefix string) map[string][]string { 59 | ret := _m.Called(prefix) 60 | 61 | var r0 map[string][]string 62 | if rf, ok := ret.Get(0).(func(string) map[string][]string); ok { 63 | r0 = rf(prefix) 64 | } else { 65 | if ret.Get(0) != nil { 66 | r0 = ret.Get(0).(map[string][]string) 67 | } 68 | } 69 | 70 | return r0 71 | } 72 | 73 | // Method provides a mock function with given fields: 74 | func (_m *RequestHeaderMapReadOnly) Method() volatile.String { 75 | ret := _m.Called() 76 | 77 | var r0 volatile.String 78 | if rf, ok := ret.Get(0).(func() volatile.String); ok { 79 | r0 = rf() 80 | } else { 81 | r0 = ret.Get(0).(volatile.String) 82 | } 83 | 84 | return r0 85 | } 86 | 87 | // Path provides a mock function with given fields: 88 | func (_m *RequestHeaderMapReadOnly) Path() volatile.String { 89 | ret := _m.Called() 90 | 91 | var r0 volatile.String 92 | if rf, ok := ret.Get(0).(func() volatile.String); ok { 93 | r0 = rf() 94 | } else { 95 | r0 = ret.Get(0).(volatile.String) 96 | } 97 | 98 | return r0 99 | } 100 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/request_header_map_updatable.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import mock "github.com/stretchr/testify/mock" 6 | 7 | // requestHeaderMapUpdatable is an autogenerated mock type for the requestHeaderMapUpdatable type 8 | type requestHeaderMapUpdatable struct { 9 | mock.Mock 10 | } 11 | 12 | // AddCopy provides a mock function with given fields: name, value 13 | func (_m *requestHeaderMapUpdatable) AddCopy(name string, value string) { 14 | _m.Called(name, value) 15 | } 16 | 17 | // AppendCopy provides a mock function with given fields: name, value 18 | func (_m *requestHeaderMapUpdatable) AppendCopy(name string, value string) { 19 | _m.Called(name, value) 20 | } 21 | 22 | // Remove provides a mock function with given fields: name 23 | func (_m *requestHeaderMapUpdatable) Remove(name string) { 24 | _m.Called(name) 25 | } 26 | 27 | // SetCopy provides a mock function with given fields: name, value 28 | func (_m *requestHeaderMapUpdatable) SetCopy(name string, value string) { 29 | _m.Called(name, value) 30 | } 31 | 32 | // SetPath provides a mock function with given fields: path 33 | func (_m *requestHeaderMapUpdatable) SetPath(path string) { 34 | _m.Called(path) 35 | } 36 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/request_or_response_header_map.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | volatile "github.com/grab/ego/ego/src/go/volatile" 7 | mock "github.com/stretchr/testify/mock" 8 | ) 9 | 10 | // RequestOrResponseHeaderMap is an autogenerated mock type for the RequestOrResponseHeaderMap type 11 | type RequestOrResponseHeaderMap struct { 12 | mock.Mock 13 | } 14 | 15 | // AddCopy provides a mock function with given fields: name, value 16 | func (_m *RequestOrResponseHeaderMap) AddCopy(name string, value string) { 17 | _m.Called(name, value) 18 | } 19 | 20 | // AppendCopy provides a mock function with given fields: name, value 21 | func (_m *RequestOrResponseHeaderMap) AppendCopy(name string, value string) { 22 | _m.Called(name, value) 23 | } 24 | 25 | // ContentType provides a mock function with given fields: 26 | func (_m *RequestOrResponseHeaderMap) ContentType() volatile.String { 27 | ret := _m.Called() 28 | 29 | var r0 volatile.String 30 | if rf, ok := ret.Get(0).(func() volatile.String); ok { 31 | r0 = rf() 32 | } else { 33 | r0 = ret.Get(0).(volatile.String) 34 | } 35 | 36 | return r0 37 | } 38 | 39 | // Get provides a mock function with given fields: name 40 | func (_m *RequestOrResponseHeaderMap) Get(name string) volatile.String { 41 | ret := _m.Called(name) 42 | 43 | var r0 volatile.String 44 | if rf, ok := ret.Get(0).(func(string) volatile.String); ok { 45 | r0 = rf(name) 46 | } else { 47 | r0 = ret.Get(0).(volatile.String) 48 | } 49 | 50 | return r0 51 | } 52 | 53 | // Remove provides a mock function with given fields: name 54 | func (_m *RequestOrResponseHeaderMap) Remove(name string) { 55 | _m.Called(name) 56 | } 57 | 58 | // SetCopy provides a mock function with given fields: name, value 59 | func (_m *RequestOrResponseHeaderMap) SetCopy(name string, value string) { 60 | _m.Called(name, value) 61 | } 62 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/request_or_response_header_map_read_only.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | volatile "github.com/grab/ego/ego/src/go/volatile" 7 | mock "github.com/stretchr/testify/mock" 8 | ) 9 | 10 | // RequestOrResponseHeaderMapReadOnly is an autogenerated mock type for the RequestOrResponseHeaderMapReadOnly type 11 | type RequestOrResponseHeaderMapReadOnly struct { 12 | mock.Mock 13 | } 14 | 15 | // ContentType provides a mock function with given fields: 16 | func (_m *RequestOrResponseHeaderMapReadOnly) ContentType() volatile.String { 17 | ret := _m.Called() 18 | 19 | var r0 volatile.String 20 | if rf, ok := ret.Get(0).(func() volatile.String); ok { 21 | r0 = rf() 22 | } else { 23 | r0 = ret.Get(0).(volatile.String) 24 | } 25 | 26 | return r0 27 | } 28 | 29 | // Get provides a mock function with given fields: name 30 | func (_m *RequestOrResponseHeaderMapReadOnly) Get(name string) volatile.String { 31 | ret := _m.Called(name) 32 | 33 | var r0 volatile.String 34 | if rf, ok := ret.Get(0).(func(string) volatile.String); ok { 35 | r0 = rf(name) 36 | } else { 37 | r0 = ret.Get(0).(volatile.String) 38 | } 39 | 40 | return r0 41 | } 42 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/request_or_response_header_map_updatable.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import mock "github.com/stretchr/testify/mock" 6 | 7 | // requestOrResponseHeaderMapUpdatable is an autogenerated mock type for the requestOrResponseHeaderMapUpdatable type 8 | type requestOrResponseHeaderMapUpdatable struct { 9 | mock.Mock 10 | } 11 | 12 | // AddCopy provides a mock function with given fields: name, value 13 | func (_m *requestOrResponseHeaderMapUpdatable) AddCopy(name string, value string) { 14 | _m.Called(name, value) 15 | } 16 | 17 | // AppendCopy provides a mock function with given fields: name, value 18 | func (_m *requestOrResponseHeaderMapUpdatable) AppendCopy(name string, value string) { 19 | _m.Called(name, value) 20 | } 21 | 22 | // Remove provides a mock function with given fields: name 23 | func (_m *requestOrResponseHeaderMapUpdatable) Remove(name string) { 24 | _m.Called(name) 25 | } 26 | 27 | // SetCopy provides a mock function with given fields: name, value 28 | func (_m *requestOrResponseHeaderMapUpdatable) SetCopy(name string, value string) { 29 | _m.Called(name, value) 30 | } 31 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/request_trailer_map.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | volatile "github.com/grab/ego/ego/src/go/volatile" 7 | mock "github.com/stretchr/testify/mock" 8 | ) 9 | 10 | // RequestTrailerMap is an autogenerated mock type for the RequestTrailerMap type 11 | type RequestTrailerMap struct { 12 | mock.Mock 13 | } 14 | 15 | // AddCopy provides a mock function with given fields: name, value 16 | func (_m *RequestTrailerMap) AddCopy(name string, value string) { 17 | _m.Called(name, value) 18 | } 19 | 20 | // AppendCopy provides a mock function with given fields: name, value 21 | func (_m *RequestTrailerMap) AppendCopy(name string, value string) { 22 | _m.Called(name, value) 23 | } 24 | 25 | // Get provides a mock function with given fields: name 26 | func (_m *RequestTrailerMap) Get(name string) volatile.String { 27 | ret := _m.Called(name) 28 | 29 | var r0 volatile.String 30 | if rf, ok := ret.Get(0).(func(string) volatile.String); ok { 31 | r0 = rf(name) 32 | } else { 33 | r0 = ret.Get(0).(volatile.String) 34 | } 35 | 36 | return r0 37 | } 38 | 39 | // Remove provides a mock function with given fields: name 40 | func (_m *RequestTrailerMap) Remove(name string) { 41 | _m.Called(name) 42 | } 43 | 44 | // SetCopy provides a mock function with given fields: name, value 45 | func (_m *RequestTrailerMap) SetCopy(name string, value string) { 46 | _m.Called(name, value) 47 | } 48 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/request_trailer_map_read_only.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | volatile "github.com/grab/ego/ego/src/go/volatile" 7 | mock "github.com/stretchr/testify/mock" 8 | ) 9 | 10 | // RequestTrailerMapReadOnly is an autogenerated mock type for the RequestTrailerMapReadOnly type 11 | type RequestTrailerMapReadOnly struct { 12 | mock.Mock 13 | } 14 | 15 | // Get provides a mock function with given fields: name 16 | func (_m *RequestTrailerMapReadOnly) Get(name string) volatile.String { 17 | ret := _m.Called(name) 18 | 19 | var r0 volatile.String 20 | if rf, ok := ret.Get(0).(func(string) volatile.String); ok { 21 | r0 = rf(name) 22 | } else { 23 | r0 = ret.Get(0).(volatile.String) 24 | } 25 | 26 | return r0 27 | } 28 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/request_trailer_map_updatable.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import mock "github.com/stretchr/testify/mock" 6 | 7 | // requestTrailerMapUpdatable is an autogenerated mock type for the requestTrailerMapUpdatable type 8 | type requestTrailerMapUpdatable struct { 9 | mock.Mock 10 | } 11 | 12 | // AddCopy provides a mock function with given fields: name, value 13 | func (_m *requestTrailerMapUpdatable) AddCopy(name string, value string) { 14 | _m.Called(name, value) 15 | } 16 | 17 | // AppendCopy provides a mock function with given fields: name, value 18 | func (_m *requestTrailerMapUpdatable) AppendCopy(name string, value string) { 19 | _m.Called(name, value) 20 | } 21 | 22 | // Remove provides a mock function with given fields: name 23 | func (_m *requestTrailerMapUpdatable) Remove(name string) { 24 | _m.Called(name) 25 | } 26 | 27 | // SetCopy provides a mock function with given fields: name, value 28 | func (_m *requestTrailerMapUpdatable) SetCopy(name string, value string) { 29 | _m.Called(name, value) 30 | } 31 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/response_header_map.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | volatile "github.com/grab/ego/ego/src/go/volatile" 7 | mock "github.com/stretchr/testify/mock" 8 | ) 9 | 10 | // ResponseHeaderMap is an autogenerated mock type for the ResponseHeaderMap type 11 | type ResponseHeaderMap struct { 12 | mock.Mock 13 | } 14 | 15 | // AddCopy provides a mock function with given fields: name, value 16 | func (_m *ResponseHeaderMap) AddCopy(name string, value string) { 17 | _m.Called(name, value) 18 | } 19 | 20 | // AppendCopy provides a mock function with given fields: name, value 21 | func (_m *ResponseHeaderMap) AppendCopy(name string, value string) { 22 | _m.Called(name, value) 23 | } 24 | 25 | // ContentType provides a mock function with given fields: 26 | func (_m *ResponseHeaderMap) ContentType() volatile.String { 27 | ret := _m.Called() 28 | 29 | var r0 volatile.String 30 | if rf, ok := ret.Get(0).(func() volatile.String); ok { 31 | r0 = rf() 32 | } else { 33 | r0 = ret.Get(0).(volatile.String) 34 | } 35 | 36 | return r0 37 | } 38 | 39 | // Get provides a mock function with given fields: name 40 | func (_m *ResponseHeaderMap) Get(name string) volatile.String { 41 | ret := _m.Called(name) 42 | 43 | var r0 volatile.String 44 | if rf, ok := ret.Get(0).(func(string) volatile.String); ok { 45 | r0 = rf(name) 46 | } else { 47 | r0 = ret.Get(0).(volatile.String) 48 | } 49 | 50 | return r0 51 | } 52 | 53 | // Remove provides a mock function with given fields: name 54 | func (_m *ResponseHeaderMap) Remove(name string) { 55 | _m.Called(name) 56 | } 57 | 58 | // SetCopy provides a mock function with given fields: name, value 59 | func (_m *ResponseHeaderMap) SetCopy(name string, value string) { 60 | _m.Called(name, value) 61 | } 62 | 63 | // SetStatus provides a mock function with given fields: status 64 | func (_m *ResponseHeaderMap) SetStatus(status int) { 65 | _m.Called(status) 66 | } 67 | 68 | // Status provides a mock function with given fields: 69 | func (_m *ResponseHeaderMap) Status() volatile.String { 70 | ret := _m.Called() 71 | 72 | var r0 volatile.String 73 | if rf, ok := ret.Get(0).(func() volatile.String); ok { 74 | r0 = rf() 75 | } else { 76 | r0 = ret.Get(0).(volatile.String) 77 | } 78 | 79 | return r0 80 | } 81 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/response_header_map_read_only.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | volatile "github.com/grab/ego/ego/src/go/volatile" 7 | mock "github.com/stretchr/testify/mock" 8 | ) 9 | 10 | // ResponseHeaderMapReadOnly is an autogenerated mock type for the ResponseHeaderMapReadOnly type 11 | type ResponseHeaderMapReadOnly struct { 12 | mock.Mock 13 | } 14 | 15 | // ContentType provides a mock function with given fields: 16 | func (_m *ResponseHeaderMapReadOnly) ContentType() volatile.String { 17 | ret := _m.Called() 18 | 19 | var r0 volatile.String 20 | if rf, ok := ret.Get(0).(func() volatile.String); ok { 21 | r0 = rf() 22 | } else { 23 | r0 = ret.Get(0).(volatile.String) 24 | } 25 | 26 | return r0 27 | } 28 | 29 | // Get provides a mock function with given fields: name 30 | func (_m *ResponseHeaderMapReadOnly) Get(name string) volatile.String { 31 | ret := _m.Called(name) 32 | 33 | var r0 volatile.String 34 | if rf, ok := ret.Get(0).(func(string) volatile.String); ok { 35 | r0 = rf(name) 36 | } else { 37 | r0 = ret.Get(0).(volatile.String) 38 | } 39 | 40 | return r0 41 | } 42 | 43 | // Status provides a mock function with given fields: 44 | func (_m *ResponseHeaderMapReadOnly) Status() volatile.String { 45 | ret := _m.Called() 46 | 47 | var r0 volatile.String 48 | if rf, ok := ret.Get(0).(func() volatile.String); ok { 49 | r0 = rf() 50 | } else { 51 | r0 = ret.Get(0).(volatile.String) 52 | } 53 | 54 | return r0 55 | } 56 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/response_header_map_updatable.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import mock "github.com/stretchr/testify/mock" 6 | 7 | // responseHeaderMapUpdatable is an autogenerated mock type for the responseHeaderMapUpdatable type 8 | type responseHeaderMapUpdatable struct { 9 | mock.Mock 10 | } 11 | 12 | // AddCopy provides a mock function with given fields: name, value 13 | func (_m *responseHeaderMapUpdatable) AddCopy(name string, value string) { 14 | _m.Called(name, value) 15 | } 16 | 17 | // AppendCopy provides a mock function with given fields: name, value 18 | func (_m *responseHeaderMapUpdatable) AppendCopy(name string, value string) { 19 | _m.Called(name, value) 20 | } 21 | 22 | // Remove provides a mock function with given fields: name 23 | func (_m *responseHeaderMapUpdatable) Remove(name string) { 24 | _m.Called(name) 25 | } 26 | 27 | // SetCopy provides a mock function with given fields: name, value 28 | func (_m *responseHeaderMapUpdatable) SetCopy(name string, value string) { 29 | _m.Called(name, value) 30 | } 31 | 32 | // SetStatus provides a mock function with given fields: status 33 | func (_m *responseHeaderMapUpdatable) SetStatus(status int) { 34 | _m.Called(status) 35 | } 36 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/route.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | envoy "github.com/grab/ego/ego/src/go/envoy" 7 | mock "github.com/stretchr/testify/mock" 8 | ) 9 | 10 | // Route is an autogenerated mock type for the Route type 11 | type Route struct { 12 | mock.Mock 13 | } 14 | 15 | // RouteEntry provides a mock function with given fields: 16 | func (_m *Route) RouteEntry() envoy.RouteEntry { 17 | ret := _m.Called() 18 | 19 | var r0 envoy.RouteEntry 20 | if rf, ok := ret.Get(0).(func() envoy.RouteEntry); ok { 21 | r0 = rf() 22 | } else { 23 | if ret.Get(0) != nil { 24 | r0 = ret.Get(0).(envoy.RouteEntry) 25 | } 26 | } 27 | 28 | return r0 29 | } 30 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/route_entry.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | envoy "github.com/grab/ego/ego/src/go/envoy" 7 | mock "github.com/stretchr/testify/mock" 8 | ) 9 | 10 | // RouteEntry is an autogenerated mock type for the RouteEntry type 11 | type RouteEntry struct { 12 | mock.Mock 13 | } 14 | 15 | // PathMatchCriterion provides a mock function with given fields: 16 | func (_m *RouteEntry) PathMatchCriterion() envoy.PathMatchCriterion { 17 | ret := _m.Called() 18 | 19 | var r0 envoy.PathMatchCriterion 20 | if rf, ok := ret.Get(0).(func() envoy.PathMatchCriterion); ok { 21 | r0 = rf() 22 | } else { 23 | if ret.Get(0) != nil { 24 | r0 = ret.Get(0).(envoy.PathMatchCriterion) 25 | } 26 | } 27 | 28 | return r0 29 | } 30 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/scope.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | envoy "github.com/grab/ego/ego/src/go/envoy" 7 | mock "github.com/stretchr/testify/mock" 8 | 9 | stats "github.com/grab/ego/ego/src/go/envoy/stats" 10 | ) 11 | 12 | // Scope is an autogenerated mock type for the Scope type 13 | type Scope struct { 14 | mock.Mock 15 | } 16 | 17 | // CounterFromStatName provides a mock function with given fields: name 18 | func (_m *Scope) CounterFromStatName(name string) envoy.Counter { 19 | ret := _m.Called(name) 20 | 21 | var r0 envoy.Counter 22 | if rf, ok := ret.Get(0).(func(string) envoy.Counter); ok { 23 | r0 = rf(name) 24 | } else { 25 | if ret.Get(0) != nil { 26 | r0 = ret.Get(0).(envoy.Counter) 27 | } 28 | } 29 | 30 | return r0 31 | } 32 | 33 | // GaugeFromStatName provides a mock function with given fields: name, importMode 34 | func (_m *Scope) GaugeFromStatName(name string, importMode stats.ImportMode) envoy.Gauge { 35 | ret := _m.Called(name, importMode) 36 | 37 | var r0 envoy.Gauge 38 | if rf, ok := ret.Get(0).(func(string, stats.ImportMode) envoy.Gauge); ok { 39 | r0 = rf(name, importMode) 40 | } else { 41 | if ret.Get(0) != nil { 42 | r0 = ret.Get(0).(envoy.Gauge) 43 | } 44 | } 45 | 46 | return r0 47 | } 48 | 49 | // HistogramFromStatName provides a mock function with given fields: name, unit 50 | func (_m *Scope) HistogramFromStatName(name string, unit stats.Unit) envoy.Histogram { 51 | ret := _m.Called(name, unit) 52 | 53 | var r0 envoy.Histogram 54 | if rf, ok := ret.Get(0).(func(string, stats.Unit) envoy.Histogram); ok { 55 | r0 = rf(name, unit) 56 | } else { 57 | if ret.Get(0) != nil { 58 | r0 = ret.Get(0).(envoy.Histogram) 59 | } 60 | } 61 | 62 | return r0 63 | } 64 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/span.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | envoy "github.com/grab/ego/ego/src/go/envoy" 7 | mock "github.com/stretchr/testify/mock" 8 | ) 9 | 10 | // Span is an autogenerated mock type for the Span type 11 | type Span struct { 12 | mock.Mock 13 | } 14 | 15 | // FinishSpan provides a mock function with given fields: 16 | func (_m *Span) FinishSpan() { 17 | _m.Called() 18 | } 19 | 20 | // GetContext provides a mock function with given fields: 21 | func (_m *Span) GetContext() map[string][]string { 22 | ret := _m.Called() 23 | 24 | var r0 map[string][]string 25 | if rf, ok := ret.Get(0).(func() map[string][]string); ok { 26 | r0 = rf() 27 | } else { 28 | if ret.Get(0) != nil { 29 | r0 = ret.Get(0).(map[string][]string) 30 | } 31 | } 32 | 33 | return r0 34 | } 35 | 36 | // SpawnChild provides a mock function with given fields: name 37 | func (_m *Span) SpawnChild(name string) envoy.Span { 38 | ret := _m.Called(name) 39 | 40 | var r0 envoy.Span 41 | if rf, ok := ret.Get(0).(func(string) envoy.Span); ok { 42 | r0 = rf(name) 43 | } else { 44 | if ret.Get(0) != nil { 45 | r0 = ret.Get(0).(envoy.Span) 46 | } 47 | } 48 | 49 | return r0 50 | } 51 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/stream_filter_callbacks.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | envoy "github.com/grab/ego/ego/src/go/envoy" 7 | mock "github.com/stretchr/testify/mock" 8 | ) 9 | 10 | // StreamFilterCallbacks is an autogenerated mock type for the StreamFilterCallbacks type 11 | type StreamFilterCallbacks struct { 12 | mock.Mock 13 | } 14 | 15 | // ActiveSpan provides a mock function with given fields: 16 | func (_m *StreamFilterCallbacks) ActiveSpan() envoy.Span { 17 | ret := _m.Called() 18 | 19 | var r0 envoy.Span 20 | if rf, ok := ret.Get(0).(func() envoy.Span); ok { 21 | r0 = rf() 22 | } else { 23 | if ret.Get(0) != nil { 24 | r0 = ret.Get(0).(envoy.Span) 25 | } 26 | } 27 | 28 | return r0 29 | } 30 | 31 | // Route provides a mock function with given fields: 32 | func (_m *StreamFilterCallbacks) Route() envoy.Route { 33 | ret := _m.Called() 34 | 35 | var r0 envoy.Route 36 | if rf, ok := ret.Get(0).(func() envoy.Route); ok { 37 | r0 = rf() 38 | } else { 39 | if ret.Get(0) != nil { 40 | r0 = ret.Get(0).(envoy.Route) 41 | } 42 | } 43 | 44 | return r0 45 | } 46 | 47 | // RouteExisting provides a mock function with given fields: 48 | func (_m *StreamFilterCallbacks) RouteExisting() bool { 49 | ret := _m.Called() 50 | 51 | var r0 bool 52 | if rf, ok := ret.Get(0).(func() bool); ok { 53 | r0 = rf() 54 | } else { 55 | r0 = ret.Get(0).(bool) 56 | } 57 | 58 | return r0 59 | } 60 | 61 | // StreamInfo provides a mock function with given fields: 62 | func (_m *StreamFilterCallbacks) StreamInfo() envoy.StreamInfo { 63 | ret := _m.Called() 64 | 65 | var r0 envoy.StreamInfo 66 | if rf, ok := ret.Get(0).(func() envoy.StreamInfo); ok { 67 | r0 = rf() 68 | } else { 69 | if ret.Get(0) != nil { 70 | r0 = ret.Get(0).(envoy.StreamInfo) 71 | } 72 | } 73 | 74 | return r0 75 | } 76 | -------------------------------------------------------------------------------- /ego/test/go/mock/gen/envoy/stream_info.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | envoy "github.com/grab/ego/ego/src/go/envoy" 7 | mock "github.com/stretchr/testify/mock" 8 | 9 | volatile "github.com/grab/ego/ego/src/go/volatile" 10 | ) 11 | 12 | // StreamInfo is an autogenerated mock type for the StreamInfo type 13 | type StreamInfo struct { 14 | mock.Mock 15 | } 16 | 17 | // FilterState provides a mock function with given fields: 18 | func (_m *StreamInfo) FilterState() envoy.FilterState { 19 | ret := _m.Called() 20 | 21 | var r0 envoy.FilterState 22 | if rf, ok := ret.Get(0).(func() envoy.FilterState); ok { 23 | r0 = rf() 24 | } else { 25 | if ret.Get(0) != nil { 26 | r0 = ret.Get(0).(envoy.FilterState) 27 | } 28 | } 29 | 30 | return r0 31 | } 32 | 33 | // GetRequestHeaders provides a mock function with given fields: 34 | func (_m *StreamInfo) GetRequestHeaders() envoy.RequestHeaderMapReadOnly { 35 | ret := _m.Called() 36 | 37 | var r0 envoy.RequestHeaderMapReadOnly 38 | if rf, ok := ret.Get(0).(func() envoy.RequestHeaderMapReadOnly); ok { 39 | r0 = rf() 40 | } else { 41 | if ret.Get(0) != nil { 42 | r0 = ret.Get(0).(envoy.RequestHeaderMapReadOnly) 43 | } 44 | } 45 | 46 | return r0 47 | } 48 | 49 | // LastDownstreamTxByteSent provides a mock function with given fields: 50 | func (_m *StreamInfo) LastDownstreamTxByteSent() int64 { 51 | ret := _m.Called() 52 | 53 | var r0 int64 54 | if rf, ok := ret.Get(0).(func() int64); ok { 55 | r0 = rf() 56 | } else { 57 | r0 = ret.Get(0).(int64) 58 | } 59 | 60 | return r0 61 | } 62 | 63 | // ResponseCode provides a mock function with given fields: 64 | func (_m *StreamInfo) ResponseCode() int { 65 | ret := _m.Called() 66 | 67 | var r0 int 68 | if rf, ok := ret.Get(0).(func() int); ok { 69 | r0 = rf() 70 | } else { 71 | r0 = ret.Get(0).(int) 72 | } 73 | 74 | return r0 75 | } 76 | 77 | // ResponseCodeDetails provides a mock function with given fields: 78 | func (_m *StreamInfo) ResponseCodeDetails() volatile.String { 79 | ret := _m.Called() 80 | 81 | var r0 volatile.String 82 | if rf, ok := ret.Get(0).(func() volatile.String); ok { 83 | r0 = rf() 84 | } else { 85 | r0 = ret.Get(0).(volatile.String) 86 | } 87 | 88 | return r0 89 | } 90 | -------------------------------------------------------------------------------- /ego/test/go/mock/logger.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package mock 7 | 8 | import ( 9 | "fmt" 10 | 11 | "github.com/grab/ego/ego/src/go/envoy/loglevel" 12 | ) 13 | 14 | type NativeLogger struct{} 15 | 16 | // Log ... 17 | func (l NativeLogger) Log(level loglevel.Type, tag, message string) { 18 | fmt.Printf("[%v]: %v\n", tag, message) 19 | } 20 | -------------------------------------------------------------------------------- /egofilters/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | # 3 | # Use of this source code is governed by the Apache License 2.0 that can be 4 | # found in the LICENSE file 5 | 6 | load("@io_bazel_rules_go//go:def.bzl", "go_library") 7 | load("@envoy//bazel:envoy_build_system.bzl", "envoy_cc_library") 8 | 9 | package(default_visibility = ["//visibility:public"]) 10 | 11 | go_library( 12 | name = "go_default_library", 13 | srcs = ["filters.go"], 14 | importpath = "github.com/grab/ego/egofilters", 15 | visibility = ["//visibility:public"], 16 | deps = [ 17 | "//ego/src/go:go_default_library", 18 | "//egofilters/http/getheader:go_default_library", 19 | "//egofilters/http/security:go_default_library", 20 | ], 21 | ) 22 | 23 | # This is our "Registry" equivalent for the proto schemas. By linking 24 | # this with the envoy binary, envoy will be able to parse filter-specific 25 | # configs. 26 | # 27 | envoy_cc_library( 28 | name = "ego_filter_protos", 29 | repository = "@envoy", 30 | deps = [ 31 | "//egofilters/http/getheader/proto:pkg_cc_proto", 32 | "//egofilters/http/security/proto:pkg_cc_proto", 33 | ], 34 | ) 35 | -------------------------------------------------------------------------------- /egofilters/filters.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package egofilters 7 | 8 | import ( 9 | ego "github.com/grab/ego/ego/src/go" 10 | 11 | "github.com/grab/ego/egofilters/http/getheader" 12 | "github.com/grab/ego/egofilters/http/security" 13 | ) 14 | 15 | func init() { 16 | ego.RegisterHttpFilter("getheader", getheader.CreatFactoryFactory()) 17 | ego.RegisterHttpFilter("security", security.CreateFactoryFactory()) 18 | } 19 | -------------------------------------------------------------------------------- /egofilters/http/getheader/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | # 3 | # Use of this source code is governed by the Apache License 2.0 that can be 4 | # found in the LICENSE file 5 | 6 | load("@io_bazel_rules_go//go:def.bzl", "go_library") 7 | 8 | go_library( 9 | name = "go_default_library", 10 | srcs = [ 11 | "factory.go", 12 | "filter.go", 13 | ], 14 | importpath = "github.com/grab/ego/egofilters/http/getheader", 15 | visibility = ["//visibility:public"], 16 | deps = [ 17 | "//ego/src/go:go_default_library", 18 | "//ego/src/go/envoy:go_default_library", 19 | "//ego/src/go/envoy/headersstatus:go_default_library", 20 | "//ego/src/go/envoy/loglevel:go_default_library", 21 | "//egofilters/http/getheader/proto:go_default_library", 22 | "@com_github_golang_protobuf//proto:go_default_library", 23 | ], 24 | ) 25 | -------------------------------------------------------------------------------- /egofilters/http/getheader/factory.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package getheader 7 | 8 | import ( 9 | "github.com/golang/protobuf/proto" 10 | 11 | pb "github.com/grab/ego/egofilters/http/getheader/proto" 12 | ego "github.com/grab/ego/ego/src/go" 13 | "github.com/grab/ego/ego/src/go/envoy" 14 | ) 15 | 16 | type factory struct { 17 | } 18 | 19 | func (f factory) CreateFilterFactory(native envoy.GoHttpFilterConfig) (ego.HttpFilterFactory, error) { 20 | settings := pb.Settings{} 21 | bytes := native.Settings() // Volatile! Handle with care! 22 | if err := proto.Unmarshal([]byte(bytes), &settings); err != nil { 23 | return nil, err 24 | } 25 | if err := settings.Validate(); err != nil { 26 | return nil, err 27 | } 28 | 29 | return func(native envoy.GoHttpFilter) ego.HttpFilter { 30 | return newGetHeaderFilter(&settings, native) 31 | }, nil 32 | } 33 | 34 | // CreateRouteSpecificFilterConfig ... 35 | func (f factory) CreateRouteSpecificFilterConfig(native envoy.GoHttpFilterConfig) (interface{}, error) { 36 | return struct{}{}, nil 37 | } 38 | 39 | // CreatFactoryFactory ... 40 | func CreatFactoryFactory() ego.HttpFilterFactoryFactory { 41 | return factory{} 42 | } 43 | -------------------------------------------------------------------------------- /egofilters/http/getheader/filter.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package getheader 7 | 8 | import ( 9 | "fmt" 10 | "net/http" 11 | "time" 12 | 13 | pb "github.com/grab/ego/egofilters/http/getheader/proto" 14 | ego "github.com/grab/ego/ego/src/go" 15 | "github.com/grab/ego/ego/src/go/envoy" 16 | "github.com/grab/ego/ego/src/go/envoy/headersstatus" 17 | "github.com/grab/ego/ego/src/go/envoy/loglevel" 18 | ) 19 | 20 | type getHeaderFilter struct { 21 | ego.HttpFilterBase 22 | settings *pb.Settings 23 | // Just a simple keep requestHeaders & response of 3rdParty httpCall for OnPost callback 24 | requestHeaders envoy.RequestHeaderMap 25 | httpResponse *http.Response 26 | httpErr error 27 | } 28 | 29 | func newGetHeaderFilter(settings *pb.Settings, native envoy.GoHttpFilter) ego.HttpFilter { 30 | f := &getHeaderFilter{settings: settings} 31 | f.HttpFilterBase.Init(native) 32 | return f 33 | } 34 | 35 | func (f *getHeaderFilter) DecodeHeaders(headers envoy.RequestHeaderMap, endStream bool) headersstatus.Type { 36 | // keep headers for use later in onPost 37 | f.requestHeaders = headers 38 | 39 | f.Pin() // must do this for every go-routine 40 | go func() { 41 | defer f.Unpin() // must do this for every go-routine. Includes f.Recover() 42 | 43 | f.Context.Done() 44 | request, err := http.NewRequestWithContext(f.Context, "GET", f.settings.Src, nil) 45 | if err != nil { 46 | // Send local repsonse 47 | f.httpErr = err 48 | f.Native.Post(0) 49 | return 50 | } 51 | 52 | client := http.Client{ 53 | Timeout: 2 * time.Second, 54 | } 55 | f.httpResponse, f.httpErr = client.Do(request) 56 | 57 | // In this demo we only need one http-call at a time 58 | // so tag = 0 because we don't need to manage multiple callback 59 | f.Native.Post(0) 60 | }() 61 | // If we turn `headersstatus.Continue` on `DecodeHeaders` from Go side 62 | // Although we call a http request with a goroutine and defer `defer f.Release()` so there is a chance 63 | // for onDestroy happened before goroutine DONE and call a post to dispatcher. () 64 | return headersstatus.StopAllIterationAndWatermark 65 | } 66 | 67 | func (f *getHeaderFilter) OnPost(tag uint64) { 68 | if f.httpErr != nil { 69 | // Send local reply and not forward request to upstream 70 | errMsg := fmt.Sprintf("can not connect to srcs header", f.httpErr) 71 | f.Native.Log(loglevel.Error, errMsg) 72 | f.Native.DecoderCallbacks().SendLocalReply(http.StatusFailedDependency, errMsg, nil, "") 73 | 74 | // Don't need to ContinueDecoding here, because we don't want to continue with forward to upstream 75 | // If you try to do that OnDestoy may happen before and SendLocalReply will not have decodeCallback 76 | } else { 77 | respHeader := f.httpResponse.Header.Get(f.settings.Hdr) 78 | f.requestHeaders.AddCopy(f.settings.Key, respHeader) 79 | f.Native.DecoderCallbacks().ContinueDecoding() 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /egofilters/http/getheader/proto/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | # 3 | # Use of this source code is governed by the Apache License 2.0 that can be 4 | # found in the LICENSE file 5 | 6 | # gazelle:ignore 7 | 8 | load("@io_bazel_rules_go//proto:compiler.bzl", "go_proto_compiler") 9 | load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") 10 | load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") 11 | 12 | # This is generate proto for C-Side when we embeded in envoy config 13 | api_proto_package() 14 | 15 | # This is generate validation file 16 | go_proto_compiler( 17 | name = "pgv_plugin_go", 18 | options = ["lang=go"], 19 | plugin = "@com_envoyproxy_protoc_gen_validate//:protoc-gen-validate", 20 | suffix = ".pb.validate.go", 21 | valid_archive = False, 22 | ) 23 | 24 | # This is generate proto for G-Side usage 25 | go_proto_library( 26 | name = "go_default_library", 27 | compilers = [ 28 | "@io_bazel_rules_go//proto:go_proto", 29 | "pgv_plugin_go", 30 | ], 31 | importpath = "github.com/grab/ego/egofilters/http/getheader/proto", 32 | proto = ":pkg", # api_proto_package() generates this 33 | visibility = ["//visibility:public"], 34 | deps = [ 35 | "@com_envoyproxy_protoc_gen_validate//validate:go_default_library", 36 | "@com_github_golang_protobuf//ptypes:go_default_library", 37 | "@com_github_golang_protobuf//ptypes/any:go_default_library", 38 | "@com_google_googleapis//google/api:annotations_go_proto", 39 | ], 40 | ) 41 | -------------------------------------------------------------------------------- /egofilters/http/getheader/proto/getheader.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | syntax = "proto3"; 7 | 8 | package egodemo.getheader; 9 | 10 | import "validate/validate.proto"; 11 | 12 | message Settings { 13 | string key = 1 [ (validate.rules).string = {min_bytes : 5} ]; 14 | string src = 2 [ (validate.rules).string = {min_bytes : 1} ]; 15 | string hdr = 3 [ (validate.rules).string = {min_bytes : 1} ]; 16 | } -------------------------------------------------------------------------------- /egofilters/http/security/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | # 3 | # Use of this source code is governed by the Apache License 2.0 that can be 4 | # found in the LICENSE file 5 | 6 | load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") 7 | 8 | go_library( 9 | name = "go_default_library", 10 | srcs = [ 11 | "config.go", 12 | "factory.go", 13 | "filter.go", 14 | ], 15 | importpath = "github.com/grab/ego/egofilters/http/security", 16 | visibility = ["//visibility:public"], 17 | deps = [ 18 | "//ego/src/go:go_default_library", 19 | "//ego/src/go/envoy:go_default_library", 20 | "//ego/src/go/envoy/datastatus:go_default_library", 21 | "//ego/src/go/envoy/headersstatus:go_default_library", 22 | "//ego/src/go/envoy/lifespan:go_default_library", 23 | "//ego/src/go/envoy/statetype:go_default_library", 24 | "//ego/src/go/envoy/trailersstatus:go_default_library", 25 | "//ego/src/go/logger:go_default_library", 26 | "//egofilters/http/security/context:go_default_library", 27 | "//egofilters/http/security/proto:go_default_library", 28 | "//egofilters/http/security/verifier:go_default_library", 29 | "@com_github_golang_protobuf//proto:go_default_library", 30 | ], 31 | ) 32 | 33 | go_test( 34 | name = "go_default_test", 35 | srcs = [ 36 | "config_test.go", 37 | "factory_test.go", 38 | "filter_sign_test.go", 39 | "filter_verify_test.go", 40 | ], 41 | embed = [":go_default_library"], 42 | deps = [ 43 | "//ego/src/go/envoy/datastatus:go_default_library", 44 | "//ego/src/go/envoy/headersstatus:go_default_library", 45 | "//ego/src/go/envoy/trailersstatus:go_default_library", 46 | "//ego/src/go/volatile:go_default_library", 47 | "//ego/test/go/mock:go_default_library", 48 | "//ego/test/go/mock/gen/envoy:go_default_library", 49 | "//egofilters/http/security/context:go_default_library", 50 | "//egofilters/http/security/proto:go_default_library", 51 | "//egofilters/http/security/verifier:go_default_library", 52 | "//egofilters/mock/gen/http/security/verifier:go_default_library", 53 | "@com_github_golang_protobuf//proto:go_default_library", 54 | "@com_github_stretchr_testify//assert:go_default_library", 55 | "@com_github_stretchr_testify//mock:go_default_library", 56 | "@com_github_stretchr_testify//require:go_default_library", 57 | ], 58 | ) 59 | -------------------------------------------------------------------------------- /egofilters/http/security/config.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package security 7 | 8 | import ( 9 | "errors" 10 | 11 | "github.com/golang/protobuf/proto" 12 | 13 | "github.com/grab/ego/ego/src/go/envoy" 14 | 15 | pb "github.com/grab/ego/egofilters/http/security/proto" 16 | "github.com/grab/ego/egofilters/http/security/verifier" 17 | ) 18 | 19 | type securityStats struct { 20 | // TODO: add more metrics if needed 21 | authOK envoy.Counter 22 | authDenied envoy.Counter 23 | authError envoy.Counter 24 | } 25 | 26 | type securityConfig struct { 27 | verifiers map[string]verifier.Verifier 28 | signers map[string]verifier.Signer 29 | stats securityStats 30 | } 31 | 32 | var ( 33 | // ErrUnsupportedProvider ... 34 | ErrUnsupportedProvider = errors.New("upsupported provider type") 35 | // ErrCannotCreateStats ... 36 | ErrCannotCreateStats = errors.New("can not create stats") 37 | ) 38 | 39 | // Initialize together with filter at initial stage 40 | func createSecurityConfig(native envoy.GoHttpFilterConfig) (*securityConfig, error) { 41 | settings := &pb.Settings{} 42 | bytes := native.Settings() // Volatile! Handle with care! 43 | if err := proto.Unmarshal([]byte(bytes), settings); err != nil { 44 | return nil, err 45 | } 46 | if err := settings.Validate(); err != nil { 47 | return nil, err 48 | } 49 | 50 | verifiers := map[string]verifier.Verifier{} 51 | signers := map[string]verifier.Signer{} 52 | providers := settings.GetProviders() 53 | // TODO: use statsScope to create stats detail for every provider 54 | scope := native.Scope() 55 | authOK := scope.CounterFromStatName("auth_ok") 56 | authDenied := scope.CounterFromStatName("auth_denied") 57 | authError := scope.CounterFromStatName("auth_error") 58 | if authOK == nil || authDenied == nil || authError == nil { 59 | return nil, ErrCannotCreateStats 60 | } 61 | secStats := securityStats{ 62 | authOK: authOK, 63 | authDenied: authDenied, 64 | authError: authError, 65 | } 66 | 67 | for k, v := range providers { 68 | switch v.GetProviderType().(type) { 69 | case *pb.Provider_CustomHmacProvider: 70 | hmacProvider, _ := verifier.CreateCustomHMACProvider(v.GetCustomHmacProvider()) 71 | verifiers[k] = hmacProvider 72 | if hmacProvider != nil { 73 | signers[k] = hmacProvider 74 | } 75 | default: 76 | return nil, ErrUnsupportedProvider 77 | } 78 | 79 | } 80 | return &securityConfig{ 81 | verifiers: verifiers, 82 | signers: signers, 83 | stats: secStats, 84 | }, nil 85 | } 86 | 87 | func (c *securityConfig) findProvider(requirement *pb.Requirement) (verifier.Verifier, verifier.Signer) { 88 | // TODO: only take care of single provider for now. This needs to be 89 | // extended to handle requires_all & require_any to combine multiple 90 | // auth-types. 91 | name := requirement.GetProviderName() 92 | if name == "" { 93 | return nil, nil 94 | } 95 | return c.verifiers[name], c.signers[name] 96 | } 97 | -------------------------------------------------------------------------------- /egofilters/http/security/context/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | # 3 | # Use of this source code is governed by the Apache License 2.0 that can be 4 | # found in the LICENSE file 5 | 6 | load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") 7 | 8 | go_library( 9 | name = "go_default_library", 10 | srcs = [ 11 | "context.go", 12 | "request_context.go", 13 | "response_context.go", 14 | ], 15 | importpath = "github.com/grab/ego/egofilters/http/security/context", 16 | visibility = ["//visibility:public"], 17 | deps = [ 18 | "//ego/src/go/envoy:go_default_library", 19 | "//ego/src/go/logger:go_default_library", 20 | ], 21 | ) 22 | 23 | go_test( 24 | name = "go_default_test", 25 | srcs = [ 26 | "request_context_test.go", 27 | "response_context_test.go", 28 | ], 29 | embed = [":go_default_library"], 30 | deps = [ 31 | "@com_github_stretchr_testify//assert:go_default_library", 32 | ], 33 | ) 34 | -------------------------------------------------------------------------------- /egofilters/http/security/context/context.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package context 7 | 8 | import "github.com/grab/ego/ego/src/go/envoy" 9 | 10 | type Context interface { 11 | ActiveSpan() envoy.Span 12 | } 13 | -------------------------------------------------------------------------------- /egofilters/http/security/context/request_context_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package context 7 | 8 | import ( 9 | "testing" 10 | 11 | "github.com/stretchr/testify/assert" 12 | ) 13 | 14 | func Test_AuthResponseOK(t *testing.T) { 15 | response := AuthResponseOK() 16 | assert.NotNil(t, response) 17 | assert.Equal(t, 200, response.StatusCode) 18 | assert.Equal(t, AuthOK, response.Status) 19 | } 20 | 21 | func Test_AuthResponseUnauthorized(t *testing.T) { 22 | response := AuthResponseUnauthorized() 23 | assert.NotNil(t, response) 24 | assert.Equal(t, 401, response.StatusCode) 25 | assert.Equal(t, AuthDenied, response.Status) 26 | } 27 | 28 | func Test_AuthResponseDenied(t *testing.T) { 29 | response := AuthResponseDenied(401) 30 | assert.NotNil(t, response) 31 | assert.Equal(t, 401, response.StatusCode) 32 | assert.Equal(t, AuthDenied, response.Status) 33 | } 34 | 35 | func Test_AuthResponseError(t *testing.T) { 36 | response := AuthResponseError() 37 | assert.NotNil(t, response) 38 | assert.Equal(t, 500, response.StatusCode) 39 | assert.Equal(t, AuthError, response.Status) 40 | } 41 | -------------------------------------------------------------------------------- /egofilters/http/security/context/response_context.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package context 7 | 8 | import ( 9 | gocontext "context" 10 | "io" 11 | 12 | "github.com/grab/ego/ego/src/go/envoy" 13 | "github.com/grab/ego/ego/src/go/logger" 14 | ) 15 | 16 | // SignResponse Sign response object for a Callbacks. 17 | type SignResponse struct { 18 | StatusCode int 19 | HeadersToSet map[string]string 20 | } 21 | 22 | type ResponseCallbacks interface { 23 | OnCompleteSigning(SignResponse) 24 | } 25 | 26 | type ResponseContext interface { 27 | Context 28 | AuthResponse() AuthResponse 29 | GoContext() gocontext.Context 30 | BodyReader() io.Reader 31 | GetSecret(string) string 32 | Callbacks() ResponseCallbacks 33 | Headers() envoy.ResponseHeaderMap 34 | RequestHeaders() envoy.RequestHeaderMap 35 | Logger() logger.Logger 36 | } 37 | 38 | type responseContextImpl struct { 39 | goContext gocontext.Context 40 | authResponse AuthResponse 41 | headers envoy.ResponseHeaderMap 42 | requestHeaders envoy.RequestHeaderMap 43 | bodyReader io.Reader 44 | secrets map[string]string 45 | callbacks ResponseCallbacks 46 | logger logger.Logger 47 | activeSpan envoy.Span 48 | } 49 | 50 | func (c *responseContextImpl) AuthResponse() AuthResponse { 51 | return c.authResponse 52 | } 53 | 54 | func (c *responseContextImpl) BodyReader() io.Reader { 55 | return c.bodyReader 56 | } 57 | 58 | func (c *responseContextImpl) GoContext() gocontext.Context { 59 | return c.goContext 60 | } 61 | 62 | func (c *responseContextImpl) GetSecret(key string) string { 63 | return c.secrets[key] 64 | } 65 | 66 | func (c *responseContextImpl) Callbacks() ResponseCallbacks { 67 | return c.callbacks 68 | } 69 | 70 | func (c *responseContextImpl) Headers() envoy.ResponseHeaderMap { 71 | return c.headers 72 | } 73 | 74 | func (c *responseContextImpl) RequestHeaders() envoy.RequestHeaderMap { 75 | return c.requestHeaders 76 | } 77 | 78 | func (c *responseContextImpl) Logger() logger.Logger { 79 | return c.logger 80 | } 81 | 82 | func (c *responseContextImpl) ActiveSpan() envoy.Span { 83 | return c.activeSpan 84 | } 85 | 86 | func CreateResponseContext(callbacks ResponseCallbacks, goContext gocontext.Context, activeSpan envoy.Span, 87 | secrets map[string]string, authResponse AuthResponse, requestHeaders envoy.RequestHeaderMap, headers envoy.ResponseHeaderMap, 88 | bodyReader io.Reader, logger logger.Logger) ResponseContext { 89 | return &responseContextImpl{ 90 | callbacks: callbacks, 91 | goContext: goContext, 92 | secrets: secrets, 93 | authResponse: authResponse, 94 | requestHeaders: requestHeaders, 95 | headers: headers, 96 | bodyReader: bodyReader, 97 | logger: logger, 98 | activeSpan: activeSpan, 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /egofilters/http/security/context/response_context_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package context 7 | 8 | import ( 9 | "testing" 10 | 11 | "github.com/stretchr/testify/assert" 12 | ) 13 | 14 | func Test_AuthResponse(t *testing.T) { 15 | r := &responseContextImpl{} 16 | r.authResponse = AuthResponseOK() 17 | res := r.AuthResponse() 18 | assert.Equal(t, r.authResponse, res) 19 | } 20 | 21 | func Test_BodyReader(t *testing.T) { 22 | r := &responseContextImpl{} 23 | res := r.BodyReader() 24 | assert.Nil(t, res) 25 | } 26 | 27 | func Test_GoContext(t *testing.T) { 28 | r := &responseContextImpl{} 29 | res := r.GoContext() 30 | assert.Nil(t, res) 31 | } 32 | 33 | func Test_GetSecret(t *testing.T) { 34 | r := &responseContextImpl{} 35 | res := r.GetSecret("test") 36 | assert.Equal(t, "", res) 37 | } 38 | 39 | func Test_Callbacks(t *testing.T) { 40 | r := &responseContextImpl{} 41 | res := r.Callbacks() 42 | assert.Nil(t, res) 43 | } 44 | 45 | func Test_Headers(t *testing.T) { 46 | r := &responseContextImpl{} 47 | res := r.Headers() 48 | assert.Nil(t, res) 49 | } 50 | 51 | func Test_RequestHeaders(t *testing.T) { 52 | r := &responseContextImpl{} 53 | res := r.RequestHeaders() 54 | assert.Nil(t, res) 55 | } 56 | 57 | func Test_Logger(t *testing.T) { 58 | r := &responseContextImpl{} 59 | res := r.Logger() 60 | assert.Nil(t, res) 61 | } 62 | 63 | func Test_ActiveSpan(t *testing.T) { 64 | r := &responseContextImpl{} 65 | res := r.ActiveSpan() 66 | assert.Nil(t, res) 67 | } 68 | -------------------------------------------------------------------------------- /egofilters/http/security/factory.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package security 7 | 8 | import ( 9 | "github.com/golang/protobuf/proto" 10 | 11 | ego "github.com/grab/ego/ego/src/go" 12 | "github.com/grab/ego/ego/src/go/envoy" 13 | 14 | pb "github.com/grab/ego/egofilters/http/security/proto" 15 | ) 16 | 17 | type factory struct{} 18 | 19 | // CreateFilterFactory ... 20 | func (f factory) CreateFilterFactory(native envoy.GoHttpFilterConfig) (ego.HttpFilterFactory, error) { 21 | config, err := createSecurityConfig(native) 22 | if err != nil { 23 | return nil, err 24 | } 25 | 26 | return func(native envoy.GoHttpFilter) ego.HttpFilter { 27 | return newSecurity(native, config) 28 | }, nil 29 | } 30 | 31 | // CreateRouteSpecificFilterConfig ... 32 | func (f factory) CreateRouteSpecificFilterConfig(native envoy.GoHttpFilterConfig) (interface{}, error) { 33 | settings := pb.Requirement{} 34 | unsafeBytes := native.Settings() // Volatile! Handle with care! 35 | if err := proto.Unmarshal([]byte(unsafeBytes), &settings); err != nil { 36 | return nil, err 37 | } 38 | if err := settings.Validate(); err != nil { 39 | return nil, err 40 | } 41 | return settings, nil 42 | } 43 | 44 | // CreateFactoryFactory ... 45 | func CreateFactoryFactory() ego.HttpFilterFactoryFactory { 46 | return factory{} 47 | } 48 | -------------------------------------------------------------------------------- /egofilters/http/security/http/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | # 3 | # Use of this source code is governed by the Apache License 2.0 that can be 4 | # found in the LICENSE file 5 | 6 | load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") 7 | 8 | go_library( 9 | name = "go_default_library", 10 | srcs = ["http_client.go"], 11 | importpath = "github.com/grab/ego/egofilters/http/security/http", 12 | visibility = ["//visibility:public"], 13 | deps = ["//egofilters/http/security/context:go_default_library"], 14 | ) 15 | 16 | go_test( 17 | name = "go_default_test", 18 | srcs = ["http_client_test.go"], 19 | embed = [":go_default_library"], 20 | deps = [ 21 | "//ego/test/go/mock/gen/envoy:go_default_library", 22 | "//egofilters/mock/gen/http/security/context:go_default_library", 23 | "//egofilters/mock/gen/http/security/http:go_default_library", 24 | "@com_github_stretchr_testify//assert:go_default_library", 25 | "@com_github_stretchr_testify//mock:go_default_library", 26 | ], 27 | ) 28 | -------------------------------------------------------------------------------- /egofilters/http/security/http/http_client.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package http 7 | 8 | import ( 9 | "net/http" 10 | 11 | "github.com/grab/ego/egofilters/http/security/context" 12 | ) 13 | 14 | type HttpClient interface { 15 | Do(req *http.Request) (*http.Response, error) 16 | } 17 | 18 | type HttpClientWithCtx interface { 19 | HttpClient 20 | DoWithTracing(ctx context.Context, req *http.Request, spanName string) (*http.Response, error) 21 | } 22 | 23 | type httpClientImpl struct { 24 | HttpClient 25 | } 26 | 27 | func (client httpClientImpl) DoWithTracing(ctx context.Context, req *http.Request, spanName string) (*http.Response, error) { 28 | if len(spanName) > 0 { 29 | span := ctx.ActiveSpan().SpawnChild(spanName) 30 | defer span.FinishSpan() 31 | 32 | spanHeaders := span.GetContext() 33 | for k, vals := range spanHeaders { 34 | if len(vals) > 0 { 35 | req.Header.Add(k, vals[0]) 36 | } 37 | } 38 | } 39 | return client.Do(req) 40 | } 41 | 42 | func NewHttpClientWithCtx(client HttpClient) HttpClientWithCtx { 43 | return &httpClientImpl{client} 44 | } 45 | -------------------------------------------------------------------------------- /egofilters/http/security/http/http_client_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package http 7 | 8 | import ( 9 | "errors" 10 | "net/http" 11 | "testing" 12 | 13 | "github.com/stretchr/testify/assert" 14 | "github.com/stretchr/testify/mock" 15 | 16 | contextmocks "github.com/grab/ego/egofilters/mock/gen/http/security/context" 17 | "github.com/grab/ego/egofilters/mock/gen/http/security/http" 18 | egomocks "github.com/grab/ego/ego/test/go/mock/gen/envoy" 19 | ) 20 | 21 | func TestDoWithTracing(t *testing.T) { 22 | tcs := []struct { 23 | name string 24 | spanName string 25 | existingHeader http.Header 26 | 27 | spanContext map[string][]string 28 | expectedHeader http.Header 29 | }{ 30 | { 31 | name: "add headers to http request", 32 | spanName: "span_name", 33 | 34 | spanContext: map[string][]string{"X-Tracing-Id": {"123"}}, 35 | expectedHeader: http.Header{ 36 | "X-Tracing-Id": []string{"123"}, 37 | }, 38 | }, 39 | { 40 | name: "add multiple headers to http request", 41 | spanName: "span_name", 42 | existingHeader: http.Header{"X-Existing": {"1"}}, 43 | 44 | spanContext: map[string][]string{"X-Tracing-Id": {"125"}, "X-Span-Id": {"124", "ignored"}}, 45 | expectedHeader: http.Header{ 46 | "X-Tracing-Id": []string{"125"}, 47 | "X-Span-Id": []string{"124"}, 48 | "X-Existing": []string{"1"}, 49 | }, 50 | }, 51 | { 52 | name: "should handle nil span context", 53 | spanName: "span_name", 54 | 55 | spanContext: nil, 56 | expectedHeader: http.Header{}, 57 | }, 58 | { 59 | name: "should neither spawn child span nor add headers to http request if span name is empty", 60 | spanName: "", 61 | 62 | spanContext: map[string][]string{"X-Tracing-Id": {"123"}}, 63 | expectedHeader: http.Header{}, 64 | }, 65 | } 66 | 67 | for _, tc := range tcs { 68 | t.Run(tc.name, func(t *testing.T) { 69 | ctx := &contextmocks.Context{} 70 | 71 | childSpan := &egomocks.Span{} 72 | if len(tc.spanName) > 0 { 73 | activeSpan := &egomocks.Span{} 74 | ctx.On("ActiveSpan").Return(activeSpan) 75 | 76 | childSpan := &egomocks.Span{} 77 | activeSpan.On("SpawnChild", tc.spanName).Return(childSpan) 78 | 79 | childSpan.On("GetContext").Return(tc.spanContext) 80 | childSpan.On("FinishSpan").Times(1) 81 | } 82 | 83 | httpClient := &mocks.HttpClient{} 84 | clientWithCtx := NewHttpClientWithCtx(httpClient) 85 | 86 | httpResponse := &http.Response{} 87 | httpErr := errors.New("an error") 88 | var actualReq *http.Request 89 | httpClient.On("Do", mock.AnythingOfType("*http.Request")).Run(func(args mock.Arguments) { 90 | actualReq = args[0].(*http.Request) 91 | }).Return(httpResponse, httpErr) 92 | 93 | req, _ := http.NewRequest(http.MethodPost, "http://test.com", nil) 94 | for k, v := range tc.existingHeader { 95 | req.Header[k] = v 96 | } 97 | 98 | actualResp, actualErr := clientWithCtx.DoWithTracing(ctx, req, tc.spanName) 99 | 100 | assert.Equal(t, httpResponse, actualResp) 101 | assert.Equal(t, httpErr, actualErr) 102 | 103 | childSpan.AssertExpectations(t) 104 | httpClient.AssertExpectations(t) 105 | 106 | assert.Equal(t, tc.expectedHeader, actualReq.Header) 107 | }) 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /egofilters/http/security/proto/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | # 3 | # Use of this source code is governed by the Apache License 2.0 that can be 4 | # found in the LICENSE file 5 | 6 | # gazelle:ignore 7 | 8 | load("@io_bazel_rules_go//proto:compiler.bzl", "go_proto_compiler") 9 | load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") 10 | load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") 11 | 12 | # This is generate proto for C-Side when we embeded in envoy config 13 | api_proto_package() 14 | 15 | # This is generate validation file 16 | go_proto_compiler( 17 | name = "pgv_plugin_go", 18 | options = ["lang=go"], 19 | plugin = "@com_envoyproxy_protoc_gen_validate//:protoc-gen-validate", 20 | suffix = ".pb.validate.go", 21 | valid_archive = False, 22 | ) 23 | 24 | # This is generate proto for G-Side usage 25 | go_proto_library( 26 | name = "go_default_library", 27 | compilers = [ 28 | "@io_bazel_rules_go//proto:go_proto", 29 | "pgv_plugin_go", 30 | ], 31 | importpath = "github.com/grab/ego/egofilters/http/security/proto", 32 | proto = ":pkg", # api_proto_package() generates this 33 | visibility = ["//visibility:public"], 34 | deps = [ 35 | "@com_envoyproxy_protoc_gen_validate//validate:go_default_library", 36 | "@com_github_golang_protobuf//ptypes:go_default_library", 37 | "@com_github_golang_protobuf//ptypes/any:go_default_library", 38 | "@com_google_googleapis//google/api:annotations_go_proto", 39 | ], 40 | ) -------------------------------------------------------------------------------- /egofilters/http/security/proto/security.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | syntax = "proto3"; 7 | 8 | package ego.security; 9 | 10 | import "validate/validate.proto"; 11 | import "google/protobuf/any.proto"; 12 | import "google/protobuf/empty.proto"; 13 | 14 | message Settings { 15 | map providers = 1 [ (validate.rules).map.min_pairs = 1 ]; 16 | } 17 | 18 | // This message specifies a provider. 19 | message Provider { 20 | oneof provider_type { 21 | CustomHMACProvider custom_hmac_provider = 1; 22 | // add other providers 23 | } 24 | } 25 | 26 | // A CustomHMACProvider message specifies the information will use to verify 27 | // HMAC signature 28 | message CustomHMACProvider { 29 | string request_validation_url = 1 [ (validate.rules).string = {min_bytes : 1} ]; 30 | string response_signing_url = 2 [ (validate.rules).string = {} ]; 31 | // A bit redundant here we will improve it with SecretManagement later 32 | string service_key = 3 [ (validate.rules).string = {min_bytes : 1} ]; 33 | string service_token = 4 [ (validate.rules).string = {min_bytes : 1} ]; 34 | repeated string generated_upstream_headers = 5[ 35 | (validate.rules).repeated.unique = true, 36 | (validate.rules).repeated.items.string = {in: [ 37 | "x-custom-userid" 38 | ]}]; 39 | bool sign_resp = 6; 40 | bool tracing_enabled = 7; 41 | } 42 | 43 | // This message specifies a requirement. An empty message means verification 44 | // is not required. 45 | message Requirement { 46 | oneof requires_type { 47 | // Specify a required provider name. 48 | string provider_name = 1; 49 | 50 | // Specify list of Requirement. Their results are OR-ed. 51 | // If any one of them passes, the result is passed. 52 | RequirementOrList requires_any = 2; 53 | 54 | // Specify list of Requirement. Their results are AND-ed. 55 | // All of them must pass, if one of them fails or missing, it fails. 56 | RequirementAndList requires_all = 3; 57 | } 58 | } 59 | 60 | // This message specifies a list of RequiredProvider. 61 | // Their results are OR-ed; if any one of them passes, the result is passed 62 | message RequirementOrList { 63 | // Specify a list of Requirement. 64 | repeated Requirement requirements = 1 65 | [ (validate.rules).repeated = {min_items : 2} ]; 66 | } 67 | 68 | // This message specifies a list of RequiredProvider. 69 | // Their results are AND-ed; all of them must pass, if one of them fails or 70 | // missing, it fails. 71 | message RequirementAndList { 72 | // Specify a list of Requirement. 73 | repeated Requirement requirements = 1 74 | [ (validate.rules).repeated = {min_items : 2} ]; 75 | } 76 | -------------------------------------------------------------------------------- /egofilters/http/security/verifier/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | # 3 | # Use of this source code is governed by the Apache License 2.0 that can be 4 | # found in the LICENSE file 5 | 6 | load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") 7 | 8 | go_library( 9 | name = "go_default_library", 10 | srcs = [ 11 | "base_provider.go", 12 | "consts.go", 13 | "custom_hmac_provider.go", 14 | "custom_hmac_validator.go", 15 | "verifier.go", 16 | ], 17 | importpath = "github.com/grab/ego/egofilters/http/security/verifier", 18 | visibility = ["//visibility:public"], 19 | deps = [ 20 | "//ego/src/go/envoy:go_default_library", 21 | "//egofilters/http/security/context:go_default_library", 22 | "//egofilters/http/security/http:go_default_library", 23 | "//egofilters/http/security/proto:go_default_library", 24 | ], 25 | ) 26 | 27 | go_test( 28 | name = "go_default_test", 29 | srcs = [ 30 | "custom_hmac_provider_factory_test.go", 31 | "custom_hmac_provider_sign_required_test.go", 32 | "custom_hmac_provider_sign_test.go", 33 | "custom_hmac_provider_verify_test.go", 34 | "custom_hmac_validator_test.go", 35 | ], 36 | embed = [":go_default_library"], 37 | deps = [ 38 | "//ego/src/go/logger:go_default_library", 39 | "//ego/src/go/volatile:go_default_library", 40 | "//ego/test/go/mock:go_default_library", 41 | "//ego/test/go/mock/gen/envoy:go_default_library", 42 | "//egofilters/http/security/context:go_default_library", 43 | "//egofilters/http/security/proto:go_default_library", 44 | "//egofilters/mock/gen/http/security/context:go_default_library", 45 | "//egofilters/mock/gen/http/security/http:go_default_library", 46 | "@com_github_stretchr_testify//assert:go_default_library", 47 | "@com_github_stretchr_testify//mock:go_default_library", 48 | "@com_github_stretchr_testify//require:go_default_library", 49 | ], 50 | ) 51 | -------------------------------------------------------------------------------- /egofilters/http/security/verifier/base_provider.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package verifier 7 | 8 | import ( 9 | "github.com/grab/ego/egofilters/http/security/context" 10 | ) 11 | 12 | type baseProvider struct { 13 | } 14 | 15 | func (v *baseProvider) Verify(ctx context.RequestContext) {} 16 | 17 | func (v *baseProvider) WithBody() bool { 18 | return false 19 | } 20 | -------------------------------------------------------------------------------- /egofilters/http/security/verifier/consts.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package verifier 7 | 8 | const ( 9 | userIDHeader = "x-custom-userid" 10 | 11 | requestIDHeader = "X-Request-Id" 12 | userAgentHeader = "User-Agent" 13 | authorizationHeader = "Authorization" 14 | contentTypeHeader = "Content-Type" 15 | cacheControlHeader = "Cache-Control" 16 | ) 17 | -------------------------------------------------------------------------------- /egofilters/http/security/verifier/custom_hmac_provider_factory_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package verifier 7 | 8 | import ( 9 | "testing" 10 | 11 | "github.com/stretchr/testify/assert" 12 | "github.com/stretchr/testify/require" 13 | 14 | pb "github.com/grab/ego/egofilters/http/security/proto" 15 | ) 16 | 17 | func TestCreateCustomHMACProvider(t *testing.T) { 18 | provider, err := CreateCustomHMACProvider(&pb.CustomHMACProvider{}) 19 | 20 | require.Nil(t, err) 21 | assert.NotNil(t, provider) 22 | assert.NotNil(t, provider.getCurrentTime()) 23 | } 24 | -------------------------------------------------------------------------------- /egofilters/http/security/verifier/custom_hmac_validator.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package verifier 7 | 8 | import ( 9 | "encoding/json" 10 | "fmt" 11 | "net/http" 12 | ) 13 | 14 | type hmacSignatureValidationResponse struct { 15 | Valid bool `json:"valid"` 16 | } 17 | 18 | type isValidHMACSignatureOpt func(resp *http.Response) (bool, error) 19 | 20 | func isValidSignature(resp *http.Response) (bool, error) { 21 | if resp.StatusCode >= http.StatusInternalServerError { 22 | return false, fmt.Errorf("5xx (%v) status code", resp.StatusCode) 23 | } 24 | 25 | if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusUnauthorized { 26 | return false, nil 27 | } 28 | 29 | result := hmacSignatureValidationResponse{} 30 | err := json.NewDecoder(resp.Body).Decode(&result) 31 | if err != nil { 32 | return false, fmt.Errorf("can't parse HMAC signature check response: %v", err) 33 | } 34 | 35 | return result.Valid, nil 36 | } 37 | -------------------------------------------------------------------------------- /egofilters/http/security/verifier/verifier.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Grabtaxi Holdings PTE LTE (GRAB), All rights reserved. 2 | // 3 | // Use of this source code is governed by the Apache License 2.0 that can be 4 | // found in the LICENSE file 5 | 6 | package verifier 7 | 8 | import ( 9 | "github.com/grab/ego/ego/src/go/envoy" 10 | 11 | "github.com/grab/ego/egofilters/http/security/context" 12 | ) 13 | 14 | // Verifier ... 15 | type Verifier interface { 16 | Verify(context.RequestContext) 17 | WithBody() bool 18 | } 19 | 20 | // Signer ... 21 | type Signer interface { 22 | // Clients have to check if SigningRequired before calling Sign. 23 | Sign(context.ResponseContext) 24 | SigningRequired(headers envoy.ResponseHeaderMap, authResp context.AuthResponse) bool 25 | } 26 | -------------------------------------------------------------------------------- /egofilters/mock/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "go_default_library", 5 | srcs = ["doc.go"], 6 | importpath = "github.com/grab/ego/egofilters/mock", 7 | visibility = ["//visibility:public"], 8 | ) 9 | -------------------------------------------------------------------------------- /egofilters/mock/doc.go: -------------------------------------------------------------------------------- 1 | package mock 2 | 3 | //go:generate mockery --all --recursive=true --keeptree --case=underscore --output ./gen --dir ../ 4 | -------------------------------------------------------------------------------- /egofilters/mock/gen/http/security/context/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "go_default_library", 5 | srcs = [ 6 | "callbacks.go", 7 | "context.go", 8 | "request_context.go", 9 | "response_callbacks.go", 10 | "response_context.go", 11 | ], 12 | importpath = "github.com/grab/ego/egofilters/mock/gen/http/security/context", 13 | visibility = ["//visibility:public"], 14 | deps = [ 15 | "//ego/src/go/envoy:go_default_library", 16 | "//ego/src/go/logger:go_default_library", 17 | "//egofilters/http/security/context:go_default_library", 18 | "@com_github_stretchr_testify//mock:go_default_library", 19 | ], 20 | ) 21 | -------------------------------------------------------------------------------- /egofilters/mock/gen/http/security/context/callbacks.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | context "github.com/grab/ego/egofilters/http/security/context" 7 | mock "github.com/stretchr/testify/mock" 8 | ) 9 | 10 | // Callbacks is an autogenerated mock type for the Callbacks type 11 | type Callbacks struct { 12 | mock.Mock 13 | } 14 | 15 | // OnComplete provides a mock function with given fields: _a0 16 | func (_m *Callbacks) OnComplete(_a0 context.AuthResponse) { 17 | _m.Called(_a0) 18 | } 19 | -------------------------------------------------------------------------------- /egofilters/mock/gen/http/security/context/context.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | envoy "github.com/grab/ego/ego/src/go/envoy" 7 | mock "github.com/stretchr/testify/mock" 8 | ) 9 | 10 | // Context is an autogenerated mock type for the Context type 11 | type Context struct { 12 | mock.Mock 13 | } 14 | 15 | // ActiveSpan provides a mock function with given fields: 16 | func (_m *Context) ActiveSpan() envoy.Span { 17 | ret := _m.Called() 18 | 19 | var r0 envoy.Span 20 | if rf, ok := ret.Get(0).(func() envoy.Span); ok { 21 | r0 = rf() 22 | } else { 23 | if ret.Get(0) != nil { 24 | r0 = ret.Get(0).(envoy.Span) 25 | } 26 | } 27 | 28 | return r0 29 | } 30 | -------------------------------------------------------------------------------- /egofilters/mock/gen/http/security/context/request_context.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | context2 "context" 7 | 8 | context "github.com/grab/ego/egofilters/http/security/context" 9 | 10 | envoy "github.com/grab/ego/ego/src/go/envoy" 11 | 12 | io "io" 13 | 14 | logger "github.com/grab/ego/ego/src/go/logger" 15 | 16 | mock "github.com/stretchr/testify/mock" 17 | ) 18 | 19 | // RequestContext is an autogenerated mock type for the RequestContext type 20 | type RequestContext struct { 21 | mock.Mock 22 | } 23 | 24 | // ActiveSpan provides a mock function with given fields: 25 | func (_m *RequestContext) ActiveSpan() envoy.Span { 26 | ret := _m.Called() 27 | 28 | var r0 envoy.Span 29 | if rf, ok := ret.Get(0).(func() envoy.Span); ok { 30 | r0 = rf() 31 | } else { 32 | if ret.Get(0) != nil { 33 | r0 = ret.Get(0).(envoy.Span) 34 | } 35 | } 36 | 37 | return r0 38 | } 39 | 40 | // BodyReader provides a mock function with given fields: 41 | func (_m *RequestContext) BodyReader() io.Reader { 42 | ret := _m.Called() 43 | 44 | var r0 io.Reader 45 | if rf, ok := ret.Get(0).(func() io.Reader); ok { 46 | r0 = rf() 47 | } else { 48 | if ret.Get(0) != nil { 49 | r0 = ret.Get(0).(io.Reader) 50 | } 51 | } 52 | 53 | return r0 54 | } 55 | 56 | // Callbacks provides a mock function with given fields: 57 | func (_m *RequestContext) Callbacks() context.Callbacks { 58 | ret := _m.Called() 59 | 60 | var r0 context.Callbacks 61 | if rf, ok := ret.Get(0).(func() context.Callbacks); ok { 62 | r0 = rf() 63 | } else { 64 | if ret.Get(0) != nil { 65 | r0 = ret.Get(0).(context.Callbacks) 66 | } 67 | } 68 | 69 | return r0 70 | } 71 | 72 | // GetSecret provides a mock function with given fields: _a0 73 | func (_m *RequestContext) GetSecret(_a0 string) string { 74 | ret := _m.Called(_a0) 75 | 76 | var r0 string 77 | if rf, ok := ret.Get(0).(func(string) string); ok { 78 | r0 = rf(_a0) 79 | } else { 80 | r0 = ret.Get(0).(string) 81 | } 82 | 83 | return r0 84 | } 85 | 86 | // GoContext provides a mock function with given fields: 87 | func (_m *RequestContext) GoContext() context2.Context { 88 | ret := _m.Called() 89 | 90 | var r0 context2.Context 91 | if rf, ok := ret.Get(0).(func() context2.Context); ok { 92 | r0 = rf() 93 | } else { 94 | if ret.Get(0) != nil { 95 | r0 = ret.Get(0).(context2.Context) 96 | } 97 | } 98 | 99 | return r0 100 | } 101 | 102 | // Headers provides a mock function with given fields: 103 | func (_m *RequestContext) Headers() envoy.RequestHeaderMap { 104 | ret := _m.Called() 105 | 106 | var r0 envoy.RequestHeaderMap 107 | if rf, ok := ret.Get(0).(func() envoy.RequestHeaderMap); ok { 108 | r0 = rf() 109 | } else { 110 | if ret.Get(0) != nil { 111 | r0 = ret.Get(0).(envoy.RequestHeaderMap) 112 | } 113 | } 114 | 115 | return r0 116 | } 117 | 118 | // Logger provides a mock function with given fields: 119 | func (_m *RequestContext) Logger() logger.Logger { 120 | ret := _m.Called() 121 | 122 | var r0 logger.Logger 123 | if rf, ok := ret.Get(0).(func() logger.Logger); ok { 124 | r0 = rf() 125 | } else { 126 | if ret.Get(0) != nil { 127 | r0 = ret.Get(0).(logger.Logger) 128 | } 129 | } 130 | 131 | return r0 132 | } 133 | -------------------------------------------------------------------------------- /egofilters/mock/gen/http/security/context/response_callbacks.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | context "github.com/grab/ego/egofilters/http/security/context" 7 | mock "github.com/stretchr/testify/mock" 8 | ) 9 | 10 | // ResponseCallbacks is an autogenerated mock type for the ResponseCallbacks type 11 | type ResponseCallbacks struct { 12 | mock.Mock 13 | } 14 | 15 | // OnCompleteSigning provides a mock function with given fields: _a0 16 | func (_m *ResponseCallbacks) OnCompleteSigning(_a0 context.SignResponse) { 17 | _m.Called(_a0) 18 | } 19 | -------------------------------------------------------------------------------- /egofilters/mock/gen/http/security/http/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "go_default_library", 5 | srcs = [ 6 | "http_client.go", 7 | "http_client_with_ctx.go", 8 | ], 9 | importpath = "github.com/grab/ego/egofilters/mock/gen/http/security/http", 10 | visibility = ["//visibility:public"], 11 | deps = [ 12 | "//egofilters/http/security/context:go_default_library", 13 | "@com_github_stretchr_testify//mock:go_default_library", 14 | ], 15 | ) 16 | -------------------------------------------------------------------------------- /egofilters/mock/gen/http/security/http/http_client.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | http "net/http" 7 | 8 | mock "github.com/stretchr/testify/mock" 9 | ) 10 | 11 | // HttpClient is an autogenerated mock type for the HttpClient type 12 | type HttpClient struct { 13 | mock.Mock 14 | } 15 | 16 | // Do provides a mock function with given fields: req 17 | func (_m *HttpClient) Do(req *http.Request) (*http.Response, error) { 18 | ret := _m.Called(req) 19 | 20 | var r0 *http.Response 21 | if rf, ok := ret.Get(0).(func(*http.Request) *http.Response); ok { 22 | r0 = rf(req) 23 | } else { 24 | if ret.Get(0) != nil { 25 | r0 = ret.Get(0).(*http.Response) 26 | } 27 | } 28 | 29 | var r1 error 30 | if rf, ok := ret.Get(1).(func(*http.Request) error); ok { 31 | r1 = rf(req) 32 | } else { 33 | r1 = ret.Error(1) 34 | } 35 | 36 | return r0, r1 37 | } 38 | -------------------------------------------------------------------------------- /egofilters/mock/gen/http/security/http/http_client_with_ctx.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | http "net/http" 7 | 8 | context "github.com/grab/ego/egofilters/http/security/context" 9 | 10 | mock "github.com/stretchr/testify/mock" 11 | ) 12 | 13 | // HttpClientWithCtx is an autogenerated mock type for the HttpClientWithCtx type 14 | type HttpClientWithCtx struct { 15 | mock.Mock 16 | } 17 | 18 | // Do provides a mock function with given fields: req 19 | func (_m *HttpClientWithCtx) Do(req *http.Request) (*http.Response, error) { 20 | ret := _m.Called(req) 21 | 22 | var r0 *http.Response 23 | if rf, ok := ret.Get(0).(func(*http.Request) *http.Response); ok { 24 | r0 = rf(req) 25 | } else { 26 | if ret.Get(0) != nil { 27 | r0 = ret.Get(0).(*http.Response) 28 | } 29 | } 30 | 31 | var r1 error 32 | if rf, ok := ret.Get(1).(func(*http.Request) error); ok { 33 | r1 = rf(req) 34 | } else { 35 | r1 = ret.Error(1) 36 | } 37 | 38 | return r0, r1 39 | } 40 | 41 | // DoWithTracing provides a mock function with given fields: ctx, req, spanName 42 | func (_m *HttpClientWithCtx) DoWithTracing(ctx context.Context, req *http.Request, spanName string) (*http.Response, error) { 43 | ret := _m.Called(ctx, req, spanName) 44 | 45 | var r0 *http.Response 46 | if rf, ok := ret.Get(0).(func(context.Context, *http.Request, string) *http.Response); ok { 47 | r0 = rf(ctx, req, spanName) 48 | } else { 49 | if ret.Get(0) != nil { 50 | r0 = ret.Get(0).(*http.Response) 51 | } 52 | } 53 | 54 | var r1 error 55 | if rf, ok := ret.Get(1).(func(context.Context, *http.Request, string) error); ok { 56 | r1 = rf(ctx, req, spanName) 57 | } else { 58 | r1 = ret.Error(1) 59 | } 60 | 61 | return r0, r1 62 | } 63 | -------------------------------------------------------------------------------- /egofilters/mock/gen/http/security/proto/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "go_default_library", 5 | srcs = [ 6 | "is_provider__provider_type.go", 7 | "is_requirement__requires_type.go", 8 | ], 9 | importpath = "github.com/grab/ego/egofilters/mock/gen/http/security/proto", 10 | visibility = ["//visibility:public"], 11 | deps = ["@com_github_stretchr_testify//mock:go_default_library"], 12 | ) 13 | -------------------------------------------------------------------------------- /egofilters/mock/gen/http/security/proto/is_provider__provider_type.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import mock "github.com/stretchr/testify/mock" 6 | 7 | // isProvider_ProviderType is an autogenerated mock type for the isProvider_ProviderType type 8 | type isProvider_ProviderType struct { 9 | mock.Mock 10 | } 11 | 12 | // isProvider_ProviderType provides a mock function with given fields: 13 | func (_m *isProvider_ProviderType) isProvider_ProviderType() { 14 | _m.Called() 15 | } 16 | -------------------------------------------------------------------------------- /egofilters/mock/gen/http/security/proto/is_requirement__requires_type.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import mock "github.com/stretchr/testify/mock" 6 | 7 | // isRequirement_RequiresType is an autogenerated mock type for the isRequirement_RequiresType type 8 | type isRequirement_RequiresType struct { 9 | mock.Mock 10 | } 11 | 12 | // isRequirement_RequiresType provides a mock function with given fields: 13 | func (_m *isRequirement_RequiresType) isRequirement_RequiresType() { 14 | _m.Called() 15 | } 16 | -------------------------------------------------------------------------------- /egofilters/mock/gen/http/security/verifier/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "go_default_library", 5 | srcs = [ 6 | "get_current_time_opt.go", 7 | "is_valid_hmac_signature_opt.go", 8 | "signer.go", 9 | "verifier.go", 10 | ], 11 | importpath = "github.com/grab/ego/egofilters/mock/gen/http/security/verifier", 12 | visibility = ["//visibility:public"], 13 | deps = [ 14 | "//ego/src/go/envoy:go_default_library", 15 | "//egofilters/http/security/context:go_default_library", 16 | "@com_github_stretchr_testify//mock:go_default_library", 17 | ], 18 | ) 19 | -------------------------------------------------------------------------------- /egofilters/mock/gen/http/security/verifier/get_current_time_opt.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | time "time" 7 | 8 | mock "github.com/stretchr/testify/mock" 9 | ) 10 | 11 | // getCurrentTimeOpt is an autogenerated mock type for the getCurrentTimeOpt type 12 | type getCurrentTimeOpt struct { 13 | mock.Mock 14 | } 15 | 16 | // Execute provides a mock function with given fields: 17 | func (_m *getCurrentTimeOpt) Execute() time.Time { 18 | ret := _m.Called() 19 | 20 | var r0 time.Time 21 | if rf, ok := ret.Get(0).(func() time.Time); ok { 22 | r0 = rf() 23 | } else { 24 | r0 = ret.Get(0).(time.Time) 25 | } 26 | 27 | return r0 28 | } 29 | -------------------------------------------------------------------------------- /egofilters/mock/gen/http/security/verifier/is_valid_hmac_signature_opt.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | http "net/http" 7 | 8 | mock "github.com/stretchr/testify/mock" 9 | ) 10 | 11 | // isValidHMACSignatureOpt is an autogenerated mock type for the isValidHMACSignatureOpt type 12 | type isValidHMACSignatureOpt struct { 13 | mock.Mock 14 | } 15 | 16 | // Execute provides a mock function with given fields: resp 17 | func (_m *isValidHMACSignatureOpt) Execute(resp *http.Response) (bool, error) { 18 | ret := _m.Called(resp) 19 | 20 | var r0 bool 21 | if rf, ok := ret.Get(0).(func(*http.Response) bool); ok { 22 | r0 = rf(resp) 23 | } else { 24 | r0 = ret.Get(0).(bool) 25 | } 26 | 27 | var r1 error 28 | if rf, ok := ret.Get(1).(func(*http.Response) error); ok { 29 | r1 = rf(resp) 30 | } else { 31 | r1 = ret.Error(1) 32 | } 33 | 34 | return r0, r1 35 | } 36 | -------------------------------------------------------------------------------- /egofilters/mock/gen/http/security/verifier/signer.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | envoy "github.com/grab/ego/ego/src/go/envoy" 7 | context "github.com/grab/ego/egofilters/http/security/context" 8 | 9 | mock "github.com/stretchr/testify/mock" 10 | ) 11 | 12 | // Signer is an autogenerated mock type for the Signer type 13 | type Signer struct { 14 | mock.Mock 15 | } 16 | 17 | // Sign provides a mock function with given fields: _a0 18 | func (_m *Signer) Sign(_a0 context.ResponseContext) { 19 | _m.Called(_a0) 20 | } 21 | 22 | // SigningRequired provides a mock function with given fields: headers, authResp 23 | func (_m *Signer) SigningRequired(headers envoy.ResponseHeaderMap, authResp context.AuthResponse) bool { 24 | ret := _m.Called(headers, authResp) 25 | 26 | var r0 bool 27 | if rf, ok := ret.Get(0).(func(envoy.ResponseHeaderMap, context.AuthResponse) bool); ok { 28 | r0 = rf(headers, authResp) 29 | } else { 30 | r0 = ret.Get(0).(bool) 31 | } 32 | 33 | return r0 34 | } 35 | -------------------------------------------------------------------------------- /egofilters/mock/gen/http/security/verifier/verifier.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.5.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | context "github.com/grab/ego/egofilters/http/security/context" 7 | mock "github.com/stretchr/testify/mock" 8 | ) 9 | 10 | // Verifier is an autogenerated mock type for the Verifier type 11 | type Verifier struct { 12 | mock.Mock 13 | } 14 | 15 | // Verify provides a mock function with given fields: _a0 16 | func (_m *Verifier) Verify(_a0 context.RequestContext) { 17 | _m.Called(_a0) 18 | } 19 | 20 | // WithBody provides a mock function with given fields: 21 | func (_m *Verifier) WithBody() bool { 22 | ret := _m.Called() 23 | 24 | var r0 bool 25 | if rf, ok := ret.Get(0).(func() bool); ok { 26 | r0 = rf() 27 | } else { 28 | r0 = ret.Get(0).(bool) 29 | } 30 | 31 | return r0 32 | } 33 | -------------------------------------------------------------------------------- /external/gomockery.patch: -------------------------------------------------------------------------------- 1 | diff --git a/gomockery.bzl b/gomockery.bzl 2 | --- a/gomockery.bzl 3 | +++ b/gomockery.bzl 4 | @@ -83,7 +83,7 @@ def _go_mockery_impl(ctx): 5 | ), 6 | ] 7 | 8 | -_go_mockery = go_rule( 9 | +_go_mockery = rule( 10 | _go_mockery_impl, 11 | attrs = { 12 | "src": attr.label( 13 | @@ -127,7 +127,11 @@ _go_mockery = go_rule( 14 | cfg = "host", 15 | mandatory = False, 16 | ), 17 | - } 18 | + "_go_context_data": attr.label( 19 | + default = "@io_bazel_rules_go//:go_context_data", 20 | + ), 21 | + }, 22 | + toolchains = ["@io_bazel_rules_go//go:toolchain"], 23 | ) 24 | 25 | def _go_tool_run_shell_stdout(ctx, cmd, args, extra_inputs, outputs): 26 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/grab/ego 2 | 3 | go 1.14 4 | 5 | replace github.com/grab/ego => ./ 6 | 7 | require ( 8 | github.com/envoyproxy/protoc-gen-validate v0.4.1 9 | github.com/golang/protobuf v1.4.3 10 | github.com/stretchr/testify v1.7.0 11 | ) 12 | -------------------------------------------------------------------------------- /services/echo/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") 2 | 3 | go_library( 4 | name = "go_default_library", 5 | srcs = ["main.go"], 6 | importpath = "github.com/grab/ego/services/echo", 7 | visibility = ["//visibility:private"], 8 | ) 9 | 10 | go_binary( 11 | name = "echo", 12 | out = "echo", 13 | embed = [":go_default_library"], 14 | visibility = ["//visibility:public"], 15 | ) 16 | -------------------------------------------------------------------------------- /services/echo/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "net/http" 7 | "runtime" 8 | ) 9 | 10 | // A simple echo service that dumps request headers and body into the 11 | // response body and adds a custom header needed by one of the examples 12 | func main() { 13 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 14 | 15 | w.Header().Set("x-powered-by", runtime.Version()) 16 | w.WriteHeader(http.StatusOK) 17 | 18 | fmt.Fprintf(w, "%v %v%v\n", r.Method, r.Host, r.URL) 19 | 20 | for name, headers := range r.Header { 21 | for _, h := range headers { 22 | fmt.Fprintf(w, "%v: %v\n", name, h) 23 | } 24 | } 25 | fmt.Fprint(w, "\n") 26 | 27 | if body, err := ioutil.ReadAll(r.Body); err != nil { 28 | fmt.Fprint(w, err.Error()) 29 | } else { 30 | _, _ = w.Write(body) 31 | } 32 | }) 33 | http.ListenAndServe(":8888", nil) 34 | } 35 | -------------------------------------------------------------------------------- /services/hmac/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") 2 | 3 | go_library( 4 | name = "go_default_library", 5 | srcs = ["main.go"], 6 | importpath = "github.com/grab/ego/services/hmac", 7 | visibility = ["//visibility:private"], 8 | ) 9 | 10 | go_binary( 11 | name = "hmac", 12 | out = "hmac", 13 | embed = [":go_default_library"], 14 | visibility = ["//visibility:public"], 15 | ) 16 | -------------------------------------------------------------------------------- /services/hmac/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "net/http" 7 | ) 8 | 9 | func main() { 10 | http.HandleFunc("/verify", func(w http.ResponseWriter, r *http.Request) { 11 | // small pseudo-hmac based on sum length 12 | // signature = len(METHOD) + len(PATH) + len(BODY) 13 | reqSignature := r.Header.Get("X-Custom-Auth-Signature") 14 | reqVerb := r.Header.Get("X-Custom-Auth-Verb") 15 | reqPath := r.Header.Get("X-Custom-Auth-Path") 16 | verifedSignature := len(reqVerb) + len(reqPath) 17 | if body, err := ioutil.ReadAll(r.Body); err == nil { 18 | verifedSignature = verifedSignature + len(body) 19 | } 20 | if reqSignature == fmt.Sprintf("%v", verifedSignature) { 21 | w.WriteHeader(http.StatusOK) 22 | fmt.Fprint(w, `{"valid": true}`) 23 | } else { 24 | w.WriteHeader(http.StatusUnauthorized) 25 | fmt.Fprint(w, `{"valid": false}`) 26 | } 27 | }) 28 | 29 | http.HandleFunc("/sign", func(w http.ResponseWriter, r *http.Request) { 30 | // resp signature = str(status_code) + len(BODY) 31 | respStatusCode := r.Header.Get("X-Custom-Auth-Status-Code") 32 | bodyLen := 0 33 | if body, err := ioutil.ReadAll(r.Body); err == nil { 34 | bodyLen = len(body) 35 | } 36 | signedSignature := fmt.Sprintf("%s_%d", respStatusCode, bodyLen) 37 | w.WriteHeader(http.StatusOK) 38 | fmt.Fprintf(w, `{"signature": "%s"}`, signedSignature) 39 | }) 40 | http.ListenAndServe(":8889", nil) 41 | } 42 | -------------------------------------------------------------------------------- /tools/copy_pb_go.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | import os.path 5 | from shutil import copyfile 6 | 7 | print("Current Working Directory " , os.getcwd()) 8 | for dirpath, dirnames, filenames in os.walk("./bazel-out"): 9 | for filename in [f for f in filenames if f.endswith(".pb.go") or f.endswith(".pb.validate.go")]: 10 | name = os.path.join(dirpath, filename) 11 | parts = name.split("%/github.com/grab/ego/") 12 | if len(parts) == 1: 13 | # print("skipping " + name) 14 | continue 15 | dest = parts[1] 16 | print("copying", name, "-->", dest) 17 | os.makedirs(os.path.dirname(dest), exist_ok=True) 18 | copyfile(name, dest) 19 | -------------------------------------------------------------------------------- /tools/generate_test_coverage_report.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Clean up test logs for next run as caches are shared. 4 | rm -rf bazel-out/k8-fastbuild/testlogs 5 | 6 | bazel coverage //egofilters/... 7 | 8 | COVERAGE_DIR=./generated 9 | mkdir -p "${COVERAGE_DIR}" 10 | 11 | COVERAGE_DATA="${COVERAGE_DIR}/coverage.dat" 12 | 13 | echo "Merging coverage data..." 14 | # Merge script supports only set. 15 | echo "mode: set" > ${COVERAGE_DATA} && cat $(find -L bazel-out/k8-fastbuild/testlogs/ -name coverage.dat) | grep -v mode: | sort -r | \ 16 | awk '{if($1 != last) {print $0;last=$1}}' >> ${COVERAGE_DATA} 17 | 18 | echo "Code coverage report..." 19 | GOPATH=$(pwd)/GOPATH GO111MODULE=off go tool cover -html=generated/coverage.dat -o generated/coverage.html 20 | 21 | echo "Code coverage summary..." 22 | go tool cover -func=generated/coverage.dat 23 | 24 | echo "Coverage report is at $(pwd)/${COVERAGE_DIR}/converage.html" 25 | 26 | -------------------------------------------------------------------------------- /tools/sync.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | case $1 in 4 | "up") 5 | rsync -rlptzv --progress --exclude bazel --exclude user.bazelrc --exclude /envoy --exclude .git --exclude compile_commands.json . "$DEV_BOX_USER@$DEV_BOX_IP:~/$DEV_BOX_FOLDER_NAME" 6 | ;; 7 | "down") 8 | rsync -rlptzv --progress --delete --exclude=.git --exclude bazel --exclude user.bazelrc --exclude /envoy "$DEV_BOX_USER@$DEV_BOX_IP:~/$DEV_BOX_FOLDER_NAME/*" ./ 9 | ;; 10 | *) 11 | echo "Unknown command. Should be 'sync up' or 'sync down'" 12 | esac --------------------------------------------------------------------------------