Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dynamic_modules: adds send response #37856

Merged
merged 17 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions source/extensions/dynamic_modules/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ envoy_cc_library(
"-Wl,--export-dynamic-symbol=envoy_dynamic_module_callback_http_get_response_trailers",
"-Wl,--export-dynamic-symbol=envoy_dynamic_module_callback_http_get_response_trailers_count",
"-Wl,--export-dynamic-symbol=envoy_dynamic_module_callback_http_set_response_trailer",
"-Wl,--export-dynamic-symbol=envoy_dynamic_module_callback_http_send_response",
"-Wl,--export-dynamic-symbol=envoy_dynamic_module_callback_http_set_dynamic_metadata_number",
"-Wl,--export-dynamic-symbol=envoy_dynamic_module_callback_http_get_dynamic_metadata_number",
"-Wl,--export-dynamic-symbol=envoy_dynamic_module_callback_http_set_dynamic_metadata_string",
Expand Down
33 changes: 31 additions & 2 deletions source/extensions/dynamic_modules/abi.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,19 @@ typedef char* envoy_dynamic_module_type_buffer_module_ptr;
typedef char* envoy_dynamic_module_type_buffer_envoy_ptr;

/**
* envoy_dynamic_module_type_Header represents a key-value pair of an HTTP header owned by Envoy's
* HeaderMap.
* envoy_dynamic_module_type_module_http_header represents a key-value pair of an HTTP header owned
* by the module.
*/
typedef struct {
envoy_dynamic_module_type_buffer_module_ptr key_ptr;
size_t key_length;
envoy_dynamic_module_type_buffer_module_ptr value_ptr;
size_t value_length;
} envoy_dynamic_module_type_module_http_header;

/**
* envoy_dynamic_module_type_http_header represents a key-value pair of an HTTP header owned by
* Envoy's HeaderMap.
*/
typedef struct {
envoy_dynamic_module_type_buffer_envoy_ptr key_ptr;
Expand Down Expand Up @@ -610,6 +621,24 @@ bool envoy_dynamic_module_callback_http_set_response_trailer(
envoy_dynamic_module_type_buffer_module_ptr key, size_t key_length,
envoy_dynamic_module_type_buffer_module_ptr value, size_t value_length);

/**
* envoy_dynamic_module_callback_http_send_response is called by the module to send the response
* to the downstream.
*
* @param filter_envoy_ptr is the pointer to the DynamicModuleHttpFilter object of the
* corresponding HTTP filter.
* @param status_code is the status code of the response.
* @param headers_vector is the array of envoy_dynamic_module_type_module_http_header that contains
* the headers of the response.
* @param headers_vector_size is the size of the headers_vector.
* @param body is the pointer to the buffer of the body of the response.
* @param body_length is the length of the body.
*/
void envoy_dynamic_module_callback_http_send_response(
envoy_dynamic_module_type_http_filter_envoy_ptr filter_envoy_ptr, uint32_t status_code,
envoy_dynamic_module_type_module_http_header* headers_vector, size_t headers_vector_size,
envoy_dynamic_module_type_buffer_module_ptr body, size_t body_length);

// ------------------------ Dynamic Metadata Callbacks -------------------------

/**
Expand Down
2 changes: 1 addition & 1 deletion source/extensions/dynamic_modules/abi_version.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace DynamicModules {
#endif
// This is the ABI version calculated as a sha256 hash of the ABI header files. When the ABI
// changes, this value must change, and the correctness of this value is checked by the test.
const char* kAbiVersion = "96ecb1011dfbd8375cab07853e6491d8ac30d4fe60e685c10ec39a0674c57a25";
const char* kAbiVersion = "271744e1b0090ad28c0006e53e760a445f4ec0a27767d9ac24a1ae87795d8c01";

#ifdef __cplusplus
} // namespace DynamicModules
Expand Down
36 changes: 35 additions & 1 deletion source/extensions/dynamic_modules/sdk/rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,16 @@ pub trait EnvoyHttpFilter {
/// Returns true if the operation is successful.
fn set_response_trailer(&mut self, key: &str, value: &[u8]) -> bool;

/// Send a response to the downstream with the given status code, headers, and body.
///
/// The headers are passed as a list of key-value pairs.
fn send_response<'a>(
&mut self,
status_code: u32,
headers: Vec<(&'a str, &'a [u8])>,
body: Option<&'a [u8]>,
);

/// Get the number-typed dynamic metadata value with the given key.
/// If the metadata is not found or is the wrong type, this returns `None`.
fn get_dynamic_metadata_number(&self, namespace: &str, key: &str) -> Option<f64>;
Expand Down Expand Up @@ -477,7 +487,6 @@ impl EnvoyHttpFilter for EnvoyHttpFilterImpl {
}
}


fn get_response_trailer_value(&self, key: &str) -> Option<EnvoyBuffer> {
self.get_header_value_impl(
key,
Expand Down Expand Up @@ -515,6 +524,31 @@ impl EnvoyHttpFilter for EnvoyHttpFilterImpl {
}
}

fn send_response(&mut self, status_code: u32, headers: Vec<(&str, &[u8])>, body: Option<&[u8]>) {
let body_ptr = body.map(|s| s.as_ptr()).unwrap_or(std::ptr::null());
let body_length = body.map(|s| s.len()).unwrap_or(0);

// Note: Casting a (&str, &[u8]) to an abi::envoy_dynamic_module_type_module_http_header works
// not because of any formal layout guarantees but because:
// 1) tuples _in practice_ are laid out packed and in order
// 2) &str and &[u8] are fat pointers (pointers to DSTs), whose layouts _in practice_ are a
// pointer and length
// If these assumptions change, this will break. (Vec is guaranteed to point to a contiguous
// array, so it's safe to cast to a pointer)
let headers_ptr = headers.as_ptr() as *mut abi::envoy_dynamic_module_type_module_http_header;
bplotnick marked this conversation as resolved.
Show resolved Hide resolved

unsafe {
abi::envoy_dynamic_module_callback_http_send_response(
self.raw_ptr,
status_code,
headers_ptr,
headers.len(),
body_ptr as *mut _,
body_length,
)
}
}

fn get_dynamic_metadata_number(&self, namespace: &str, key: &str) -> Option<f64> {
let namespace_ptr = namespace.as_ptr();
let namespace_size = namespace.len();
Expand Down
25 changes: 25 additions & 0 deletions source/extensions/filters/http/dynamic_modules/abi_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,31 @@ bool envoy_dynamic_module_callback_http_get_response_trailers(
return getHeadersImpl(filter->response_trailers_, result_headers);
}

void envoy_dynamic_module_callback_http_send_response(
envoy_dynamic_module_type_http_filter_envoy_ptr filter_envoy_ptr, uint32_t status_code,
envoy_dynamic_module_type_module_http_header* headers_vector, size_t headers_vector_size,
envoy_dynamic_module_type_buffer_module_ptr body_ptr, size_t body_length) {
DynamicModuleHttpFilter* filter = static_cast<DynamicModuleHttpFilter*>(filter_envoy_ptr);

std::function<void(ResponseHeaderMap & headers)> modify_headers = nullptr;
if (headers_vector != nullptr && headers_vector_size != 0) {
modify_headers = [headers_vector, headers_vector_size](ResponseHeaderMap& headers) {
for (size_t i = 0; i < headers_vector_size; i++) {
const auto& header = &headers_vector[i];
const absl::string_view key(static_cast<const char*>(header->key_ptr), header->key_length);
const absl::string_view value(static_cast<const char*>(header->value_ptr),
header->value_length);
headers.addCopy(Http::LowerCaseString(key), value);
}
};
}
const absl::string_view body =
body_ptr ? absl::string_view(static_cast<const char*>(body_ptr), body_length) : "";

bplotnick marked this conversation as resolved.
Show resolved Hide resolved
filter->sendLocalReply(static_cast<Http::Code>(status_code), body, modify_headers, 0,
"dynamic_module");
}

/**
* Helper to get the metadata namespace from the stream info.
* @param filter_envoy_ptr is the pointer to the DynamicModuleHttpFilter object of the
Expand Down
9 changes: 7 additions & 2 deletions source/extensions/filters/http/dynamic_modules/filter.cc
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
#include "source/extensions/filters/http/dynamic_modules/filter.h"

#include "envoy/server/filter_config.h"

namespace Envoy {
namespace Extensions {
namespace DynamicModules {
Expand Down Expand Up @@ -81,6 +79,13 @@ FilterMetadataStatus DynamicModuleHttpFilter::encodeMetadata(MetadataMap&) {
return FilterMetadataStatus::Continue;
}

void DynamicModuleHttpFilter::sendLocalReply(
Code code, absl::string_view body,
std::function<void(ResponseHeaderMap& headers)> modify_headers,
const absl::optional<Grpc::Status::GrpcStatus> grpc_status, absl::string_view details) {
decoder_callbacks_->sendLocalReply(code, body, modify_headers, grpc_status, details);
}

void DynamicModuleHttpFilter::encodeComplete(){};

} // namespace HttpFilters
Expand Down
5 changes: 5 additions & 0 deletions source/extensions/filters/http/dynamic_modules/filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ class DynamicModuleHttpFilter : public Http::StreamFilter,
}
void encodeComplete() override;

void sendLocalReply(Code code, absl::string_view body,
std::function<void(ResponseHeaderMap& headers)> modify_headers,
const absl::optional<Grpc::Status::GrpcStatus> grpc_status,
absl::string_view details);

// The callbacks for the filter. They are only valid until onDestroy() is called.
StreamDecoderFilterCallbacks* decoder_callbacks_ = nullptr;
StreamEncoderFilterCallbacks* encoder_callbacks_ = nullptr;
Expand Down
Loading