Skip to content
1 change: 1 addition & 0 deletions docs/root/intro/version_history.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ Features:
- iOS: add support for integrating Envoy Mobile via the Swift Package Manager
- android: create simple persistent SharedPreferencesStore (:issue: `#2319 <2319>`)
- iOS: A documentation archive is now included in the GitHub release artifact (:issue: `#2335 <2335>`)
- api: improved C++ APIs compatibility with Java / Kotlin / Swift (:issue `#2362 <2362>`)

0.4.6 (April 26, 2022)
========================
Expand Down
2 changes: 1 addition & 1 deletion library/cc/bridge_utility.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ RawHeaderMap envoyHeadersAsRawHeaderMap(envoy_headers raw_headers) {
// free instead of release_envoy_headers
// because we already free each envoy_data individually
// during calls to envoy_data_as_string
free(raw_headers.entries);
release_envoy_headers(raw_headers);
return headers;
}

Expand Down
15 changes: 13 additions & 2 deletions library/cc/engine_builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ EngineBuilder& EngineBuilder::setDeviceOs(const std::string& device_os) {
return *this;
}

EngineBuilder& EngineBuilder::setStreamIdleTimeoutSeconds(int stream_idle_timeout_seconds) {
this->stream_idle_timeout_seconds_ = stream_idle_timeout_seconds;
return *this;
}

EngineBuilder& EngineBuilder::enableGzip(bool gzip_on) {
this->gzip_filter_ = gzip_on;
return *this;
Expand Down Expand Up @@ -166,10 +171,16 @@ EngineSharedPtr EngineBuilder::build() {

envoy_event_tracker null_tracker{};

auto config_str = this->generateConfigStr();
std::string config_str;
if (config_override_for_tests_.empty()) {
config_str = this->generateConfigStr();
} else {
config_str = config_override_for_tests_;
}
auto envoy_engine =
init_engine(this->callbacks_->asEnvoyEngineCallbacks(), null_logger, null_tracker);
run_engine(envoy_engine, config_str.c_str(), logLevelToString(this->log_level_).c_str());
run_engine(envoy_engine, config_str.c_str(), logLevelToString(this->log_level_).c_str(),
this->admin_address_path_for_tests_.c_str());

// we can't construct via std::make_shared
// because Engine is only constructible as a friend
Expand Down
6 changes: 6 additions & 0 deletions library/cc/engine_builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class EngineBuilder {
EngineBuilder& setAppVersion(const std::string& app_version);
EngineBuilder& setAppId(const std::string& app_id);
EngineBuilder& setDeviceOs(const std::string& app_id);
EngineBuilder& setStreamIdleTimeoutSeconds(int stream_idle_timeout_seconds);
EngineBuilder& enableGzip(bool gzip_on);
EngineBuilder& enableBrotli(bool brotli_on);

Expand All @@ -46,6 +47,9 @@ class EngineBuilder {
// Filter): EngineBuilder& addNativeFilter(name: String = UUID.randomUUID().toString(),
// typedConfig: String): EngineBuilder& addStringAccessor(name: String, accessor:
// EnvoyStringAccessor): EngineBuilder {
protected:
void setOverrideConfigForTests(std::string config) { config_override_for_tests_ = config; }
void setAdminAddressPathForTests(std::string admin) { admin_address_path_for_tests_ = admin; }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alternately could publicly add key-value and hash map for generic command line override.


private:
LogLevel log_level_ = LogLevel::info;
Expand All @@ -66,6 +70,8 @@ class EngineBuilder {
std::string app_id_ = "unspecified";
std::string device_os_ = "unspecified";
std::string virtual_clusters_ = "[]";
std::string config_override_for_tests_ = "";
std::string admin_address_path_for_tests_ = "";
int stream_idle_timeout_seconds_ = 15;
int per_try_idle_timeout_seconds_ = 15;
bool gzip_filter_ = true;
Expand Down
34 changes: 21 additions & 13 deletions library/cc/stream_callbacks.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ namespace Platform {

namespace {

void* c_on_headers(envoy_headers headers, bool end_stream, envoy_stream_intel, void* context) {
void* c_on_headers(envoy_headers headers, bool end_stream, envoy_stream_intel intel,
void* context) {
auto stream_callbacks = *static_cast<StreamCallbacksSharedPtr*>(context);
if (stream_callbacks->on_headers.has_value()) {
auto raw_headers = envoyHeadersAsRawHeaderMap(headers);
Expand All @@ -22,7 +23,9 @@ void* c_on_headers(envoy_headers headers, bool end_stream, envoy_stream_intel, v
builder.set(pair.first, pair.second);
}
auto on_headers = stream_callbacks->on_headers.value();
on_headers(builder.build(), end_stream);
on_headers(builder.build(), end_stream, intel);
} else {
release_envoy_headers(headers);
}
return context;
}
Expand All @@ -32,11 +35,13 @@ void* c_on_data(envoy_data data, bool end_stream, envoy_stream_intel, void* cont
if (stream_callbacks->on_data.has_value()) {
auto on_data = stream_callbacks->on_data.value();
on_data(data, end_stream);
} else {
release_envoy_data(data);
}
return context;
}

void* c_on_trailers(envoy_headers metadata, envoy_stream_intel, void* context) {
void* c_on_trailers(envoy_headers metadata, envoy_stream_intel intel, void* context) {
auto stream_callbacks = *static_cast<StreamCallbacksSharedPtr*>(context);
if (stream_callbacks->on_trailers.has_value()) {
auto raw_headers = envoyHeadersAsRawHeaderMap(metadata);
Expand All @@ -45,13 +50,15 @@ void* c_on_trailers(envoy_headers metadata, envoy_stream_intel, void* context) {
builder.set(pair.first, pair.second);
}
auto on_trailers = stream_callbacks->on_trailers.value();
on_trailers(builder.build());
on_trailers(builder.build(), intel);
} else {
release_envoy_headers(metadata);
}
return context;
}

void* c_on_error(envoy_error raw_error, envoy_stream_intel, envoy_final_stream_intel,
void* context) {
void* c_on_error(envoy_error raw_error, envoy_stream_intel intel,
envoy_final_stream_intel final_intel, void* context) {
auto stream_callbacks_ptr = static_cast<StreamCallbacksSharedPtr*>(context);
auto stream_callbacks = *stream_callbacks_ptr;
if (stream_callbacks->on_error.has_value()) {
Expand All @@ -60,40 +67,41 @@ void* c_on_error(envoy_error raw_error, envoy_stream_intel, envoy_final_stream_i
error->message = Data::Utility::copyToString(raw_error.message);
error->attempt_count = absl::optional<int>(raw_error.attempt_count);
auto on_error = stream_callbacks->on_error.value();
on_error(error);
on_error(error, intel, final_intel);
}
release_envoy_error(raw_error);
delete stream_callbacks_ptr;
return nullptr;
}

void* c_on_complete(envoy_stream_intel, envoy_final_stream_intel, void* context) {
void* c_on_complete(envoy_stream_intel intel, envoy_final_stream_intel final_intel, void* context) {
auto stream_callbacks_ptr = static_cast<StreamCallbacksSharedPtr*>(context);
auto stream_callbacks = *stream_callbacks_ptr;
if (stream_callbacks->on_complete.has_value()) {
auto on_complete = stream_callbacks->on_complete.value();
on_complete();
on_complete(intel, final_intel);
}
delete stream_callbacks_ptr;
return nullptr;
}

void* c_on_cancel(envoy_stream_intel, envoy_final_stream_intel, void* context) {
void* c_on_cancel(envoy_stream_intel intel, envoy_final_stream_intel final_intel, void* context) {
auto stream_callbacks_ptr = static_cast<StreamCallbacksSharedPtr*>(context);
auto stream_callbacks = *stream_callbacks_ptr;
if (stream_callbacks->on_cancel.has_value()) {
auto on_cancel = stream_callbacks->on_cancel.value();
on_cancel();
on_cancel(intel, final_intel);
}
delete stream_callbacks_ptr;
return nullptr;
}

void* c_on_send_window_available(envoy_stream_intel, void* context) {
void* c_on_send_window_available(envoy_stream_intel intel, void* context) {
auto stream_callbacks_ptr = static_cast<StreamCallbacksSharedPtr*>(context);
auto stream_callbacks = *stream_callbacks_ptr;
if (stream_callbacks->on_send_window_available.has_value()) {
auto on_send_window_available = stream_callbacks->on_send_window_available.value();
on_send_window_available();
on_send_window_available(intel);
}
delete stream_callbacks_ptr;
return nullptr;
Expand Down
17 changes: 11 additions & 6 deletions library/cc/stream_callbacks.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,18 @@ namespace Platform {
class Stream;
using StreamSharedPtr = std::shared_ptr<Stream>;

using OnHeadersCallback = std::function<void(ResponseHeadersSharedPtr headers, bool end_stream)>;
using OnHeadersCallback = std::function<void(ResponseHeadersSharedPtr headers, bool end_stream,
envoy_stream_intel intel)>;
using OnDataCallback = std::function<void(envoy_data data, bool end_stream)>;
using OnTrailersCallback = std::function<void(ResponseTrailersSharedPtr trailers)>;
using OnErrorCallback = std::function<void(EnvoyErrorSharedPtr error)>;
using OnCompleteCallback = std::function<void()>;
using OnCancelCallback = std::function<void()>;
using OnSendWindowAvailableCallback = std::function<void()>;
using OnTrailersCallback =
std::function<void(ResponseTrailersSharedPtr trailers, envoy_stream_intel intel)>;
using OnErrorCallback = std::function<void(EnvoyErrorSharedPtr error, envoy_stream_intel intel,
envoy_final_stream_intel final_intel)>;
using OnCompleteCallback =
std::function<void(envoy_stream_intel intel, envoy_final_stream_intel final_intel)>;
using OnCancelCallback =
std::function<void(envoy_stream_intel intel, envoy_final_stream_intel final_intel)>;
using OnSendWindowAvailableCallback = std::function<void(envoy_stream_intel intel)>;

// See library/common/types/c_types.h for what these callbacks should do.
struct StreamCallbacks : public std::enable_shared_from_this<StreamCallbacks> {
Expand Down
4 changes: 2 additions & 2 deletions library/cc/stream_prototype.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ StreamPrototype::StreamPrototype(EngineSharedPtr engine) : engine_(engine) {
this->callbacks_ = std::make_shared<StreamCallbacks>();
}

StreamSharedPtr StreamPrototype::start() {
StreamSharedPtr StreamPrototype::start(bool explicit_flow_control) {
auto envoy_stream = init_stream(this->engine_->engine_);
start_stream(this->engine_->engine_, envoy_stream, this->callbacks_->asEnvoyHttpCallbacks(),
false);
explicit_flow_control);
return std::make_shared<Stream>(this->engine_->engine_, envoy_stream);
}

Expand Down
2 changes: 1 addition & 1 deletion library/cc/stream_prototype.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class StreamPrototype {
public:
StreamPrototype(EngineSharedPtr engine);

StreamSharedPtr start();
StreamSharedPtr start(bool explicit_flow_control = false);

StreamPrototype& setOnHeaders(OnHeadersCallback closure);
StreamPrototype& setOnData(OnDataCallback closure);
Expand Down
17 changes: 12 additions & 5 deletions library/common/engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,19 @@ Engine::Engine(envoy_engine_callbacks callbacks, envoy_logger logger,
Envoy::Api::External::registerApi(std::string(envoy_event_tracker_api_name), &event_tracker_);
}

envoy_status_t Engine::run(const std::string config, const std::string log_level) {
envoy_status_t Engine::run(const std::string config, const std::string log_level,
const std::string admin_address_path) {
// Start the Envoy on the dedicated thread. Note: due to how the assignment operator works with
// std::thread, main_thread_ is the same object after this call, but its state is replaced with
// that of the temporary. The temporary object's state becomes the default state, which does
// nothing.
main_thread_ = std::thread(&Engine::main, this, std::string(config), std::string(log_level));
main_thread_ = std::thread(&Engine::main, this, std::string(config), std::string(log_level),
admin_address_path);
return ENVOY_SUCCESS;
}

envoy_status_t Engine::main(const std::string config, const std::string log_level) {
envoy_status_t Engine::main(const std::string config, const std::string log_level,
const std::string admin_address_path) {
// Using unique_ptr ensures main_common's lifespan is strictly scoped to this function.
std::unique_ptr<EngineCommon> main_common;
const std::string name = "envoy";
Expand All @@ -51,8 +54,12 @@ envoy_status_t Engine::main(const std::string config, const std::string log_leve
concurrency_option.c_str(),
concurrency_arg.c_str(),
log_flag.c_str(),
log_level.c_str(),
nullptr};
log_level.c_str()};
if (!admin_address_path.empty()) {
envoy_argv.push_back("--admin-address-path");
envoy_argv.push_back(admin_address_path.c_str());
}
envoy_argv.push_back(nullptr);
{
Thread::LockGuard lock(mutex_);
try {
Expand Down
6 changes: 4 additions & 2 deletions library/common/engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@ class Engine : public Logger::Loggable<Logger::Id::main> {
* Run the engine with the provided configuration.
* @param config, the Envoy bootstrap configuration to use.
* @param log_level, the log level.
* @param admin_address_path to set --admin-address-path, or an empty string if not needed.
*/
envoy_status_t run(std::string config, std::string log_level);
envoy_status_t run(std::string config, std::string log_level,
const std::string admin_address_path);

/**
* Immediately terminate the engine, if running.
Expand Down Expand Up @@ -128,7 +130,7 @@ class Engine : public Logger::Loggable<Logger::Id::main> {
Upstream::ClusterManager& getClusterManager();

private:
envoy_status_t main(std::string config, std::string log_level);
envoy_status_t main(std::string config, std::string log_level, std::string admin_address_path);
static void logInterfaces(absl::string_view event,
std::vector<Network::InterfacePair>& interfaces);

Expand Down
5 changes: 3 additions & 2 deletions library/common/engine_handle.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@ envoy_engine_t EngineHandle::initEngine(envoy_engine_callbacks callbacks, envoy_
return 1;
}

envoy_status_t EngineHandle::runEngine(envoy_engine_t, const char* config, const char* log_level) {
envoy_status_t EngineHandle::runEngine(envoy_engine_t, const char* config, const char* log_level,
const char* admin_address_path) {
// This will change once multiple engine support is in place.
// https://github.com/envoyproxy/envoy-mobile/issues/332
if (auto e = engine()) {
e->run(config, log_level);
e->run(config, log_level, admin_address_path);
return ENVOY_SUCCESS;
}

Expand Down
6 changes: 4 additions & 2 deletions library/common/engine_handle.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ class EngineHandle {

static envoy_engine_t initEngine(envoy_engine_callbacks callbacks, envoy_logger logger,
envoy_event_tracker event_tracker);
static envoy_status_t runEngine(envoy_engine_t, const char* config, const char* log_level);
static envoy_status_t runEngine(envoy_engine_t, const char* config, const char* log_level,
const char* admin_address_path);
static void terminateEngine(envoy_engine_t);

static EngineSharedPtr strong_engine_;
Expand All @@ -39,7 +40,8 @@ class EngineHandle {
// Allow a specific list of functions to access the internal setup/teardown functionality.
friend envoy_engine_t(::init_engine)(envoy_engine_callbacks callbacks, envoy_logger logger,
envoy_event_tracker event_tracker);
friend envoy_status_t(::run_engine)(envoy_engine_t, const char* config, const char* log_level);
friend envoy_status_t(::run_engine)(envoy_engine_t, const char* config, const char* log_level,
const char* admin_address_path);
friend void ::terminate_engine(envoy_engine_t engine);
};

Expand Down
2 changes: 1 addition & 1 deletion library/common/jni/jni_interface.cc
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ extern "C" JNIEXPORT jlong JNICALL Java_io_envoyproxy_envoymobile_engine_JniLibr
extern "C" JNIEXPORT jint JNICALL Java_io_envoyproxy_envoymobile_engine_JniLibrary_runEngine(
JNIEnv* env, jclass, jlong engine, jstring config, jstring log_level) {
return run_engine(engine, env->GetStringUTFChars(config, nullptr),
env->GetStringUTFChars(log_level, nullptr));
env->GetStringUTFChars(log_level, nullptr), "");
}

extern "C" JNIEXPORT void JNICALL Java_io_envoyproxy_envoymobile_engine_JniLibrary_terminateEngine(
Expand Down
5 changes: 3 additions & 2 deletions library/common/main_interface.cc
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,9 @@ envoy_engine_t init_engine(envoy_engine_callbacks callbacks, envoy_logger logger
return Envoy::EngineHandle::initEngine(callbacks, logger, event_tracker);
}

envoy_status_t run_engine(envoy_engine_t engine, const char* config, const char* log_level) {
return Envoy::EngineHandle::runEngine(engine, config, log_level);
envoy_status_t run_engine(envoy_engine_t engine, const char* config, const char* log_level,
const char* admin_path) {
return Envoy::EngineHandle::runEngine(engine, config, log_level, admin_path);
}

void terminate_engine(envoy_engine_t engine) { Envoy::EngineHandle::terminateEngine(engine); }
Expand Down
4 changes: 3 additions & 1 deletion library/common/main_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,9 +191,11 @@ envoy_engine_t init_engine(envoy_engine_callbacks callbacks, envoy_logger logger
* @param engine, handle to the engine to run.
* @param config, the configuration blob to run envoy with.
* @param log_level, the logging level to run envoy with.
* @param admin_path, the file path to log the admin address to if desired.
* @return envoy_status_t, the resulting status of the operation.
*/
envoy_status_t run_engine(envoy_engine_t engine, const char* config, const char* log_level);
envoy_status_t run_engine(envoy_engine_t engine, const char* config, const char* log_level,
const char* admin_path);

/**
* Terminate an engine. Further interactions with a terminated engine, or streams created by a
Expand Down
2 changes: 1 addition & 1 deletion library/objective-c/EnvoyEngineImpl.m
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,7 @@ - (int)runWithConfigYAML:(NSString *)configYAML logLevel:(NSString *)logLevel {
// Envoy exceptions will only be caught here when compiled for 64-bit arches.
// https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Exceptions/Articles/Exceptions64Bit.html
@try {
return (int)run_engine(_engineHandle, configYAML.UTF8String, logLevel.UTF8String);
return (int)run_engine(_engineHandle, configYAML.UTF8String, logLevel.UTF8String, "");
} @catch (NSException *exception) {
NSLog(@"[Envoy] exception caught: %@", exception);
[NSNotificationCenter.defaultCenter postNotificationName:@"EnvoyError" object:self];
Expand Down
Loading