From 23a93044110836baa6b131859a8958b57b17bccd Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Tue, 4 Jul 2023 08:59:35 +0000 Subject: [PATCH 01/28] Document Proxy-Wasm ABI v0.2.1. Fixes #41. Signed-off-by: Piotr Sikora --- abi-versions/v0.2.1/README.md | 1996 +++++++++++++++++++++++++++++++++ 1 file changed, 1996 insertions(+) create mode 100644 abi-versions/v0.2.1/README.md diff --git a/abi-versions/v0.2.1/README.md b/abi-versions/v0.2.1/README.md new file mode 100644 index 0000000..307703b --- /dev/null +++ b/abi-versions/v0.2.1/README.md @@ -0,0 +1,1996 @@ +# Proxy-Wasm ABI v0.2.1 specification + +--- + +Status: **FINAL** + +--- + +# Callbacks and Functions + +### Callbacks exposed by the Wasm module + +All callbacks (entry points named `proxy_on_`) are optional, +and are going to be called only if exposed by the Wasm module. + +All callbacks, other than the [integration] and [memory management] +functions, include a unique context identifier as the first parameter, +which can be used to distinguish between different contexts. + + +### Functions exposed by the host + +All functions exposed by the host are required. + +All Proxy-Wasm functions exposed by the host return [`proxy_status_t`], +which indicates status of the call (success, invalid memory access, +etc.). Return values are written into memory pointed by `return_` +parameters. + + +## Integration + +### Callbacks exposed by the Wasm module + +#### `proxy_abi_version_0_2_1` + +* params: + - none +* returns: + - none + +Function marker used during linking to advertise Wasm module's support +for Proxy-Wasm ABI v0.2.1. + +This function is never called. + + +#### `_initialize` + +* params: + - none +* returns: + - none + +Called when the Wasm module is first loaded. + + +#### `main` + +* params: + - `i32 (uint32_t) ignored` + - `i32 (uint32_t) ignored` +* returns: + - `i32 (uint32_t) ignored` + +> **Warning** +> This is called only if [`_initialize`] is also exported. + +Called when the Wasm module is first loaded, after [`_initialize`]. + + +#### `_start` + +* params: + - none +* returns: + - none + +> **Warning** +> This is called only if [`_initialize`] is not exported. + +Called when the Wasm module is first loaded. + + +## Memory management + +### Callbacks exposed by the Wasm module + +#### `proxy_on_memory_allocate` + +* params: + - `i32 (size_t) memory_size` +* returns: + - `i32 (uint8_t *) memory_data` + +Called to allocate continuous memory buffer of `memory_size` using +the in-VM memory allocator. + +Plugin must return `memory_data` pointing to the start of the allocated +memory. + +Returning `0` indicates failure. + + +#### `malloc` + +* params: + - `i32 (size_t) memory_size` +* returns: + - `i32 (uint8_t *) memory_data` + +> **Warning** +> This callback has been deprecated in favor of [`proxy_on_memory_allocate`], +> and it's called only in its absence. + +Called to allocate continuous memory buffer of `memory_size` using +the in-VM memory allocator. + +Plugin must return `memory_data` pointing to the start of the allocated +memory. + +Returning `0` indicates failure. + + +## Context lifecycle + +### Callbacks exposed by the Wasm module + +#### `proxy_on_context_create` + +* params: + - `i32 (uint32_t) context_id` + - `i32 (uint32_t) parent_context_id` +* returns: + - none + +Called when the host creates a new context (`context_id`). + +When `parent_context_id` is `0` then a new plugin context is created, +otherwise a new per-stream context is created. + + +#### `proxy_on_done` + +* params: + - `i32 (uint32_t) context_id` +* returns: + - `i32 (bool) completed` + +Called when the host is done processing context (`context_id`). + +Plugin must return one of the following values: +- `true` to allow the host to finalize and delete context. +- `false` to indicate that the context is still being used, + and that plugin is going to call [`proxy_done`] later to + allow the host to finalize and delete that context. + + +#### `proxy_on_log` + +* params: + - `i32 (uint32_t) context_id` +* returns: + - none + +Called after the host is done processing context, but before +releasing its state. + +This can be used e.g. for generating final log entries. + +It's called after `true` was returned from [`proxy_on_done`] +or after a call to [`proxy_done`]. + + +#### `proxy_on_delete` + +* params: + - `i32 (uint32_t) context_id` +* returns: + - none + +Called when the host removes the context (`context_id`) to signal that +the plugin should stop tracking it and remove all associated state. + +It's called after `true` was returned from [`proxy_on_done`] +or after a call to [`proxy_done`]. + + +### Functions exposed by the host + +#### `proxy_done` + +* params: + - none +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Indicates to the host that the plugin is done processing active +context. + +This should be used after returning `false` in [`proxy_on_done`]. + +Returned `status` value is: +- `OK` on success. +- `NOT_FOUND` when active context was not pending finalization. + + +#### `proxy_set_effective_context` + +* params: + - `i32 (uint32_t) context_id` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Changes the effective context to `context_id`. + +This can be used to change active context, e.g. during +[`proxy_on_http_call_response`], [`proxy_on_grpc_receive`] +and/or [`proxy_on_queue_ready`] callbacks. + +Returned `status` value is: +- `OK` on success. +- `BAD_ARGUMENT` for unknown `context_id`. + + +## Configuration + +### Callbacks exposed by the Wasm module + +#### `proxy_on_vm_start` + +* params: + - `i32 (uint32_t) plugin_context_id` + - `i32 (size_t) vm_configuration_size` +* returns: + - `i32 (bool) status` + +Called when the host starts the WebAssembly Virtual Machine. + +Its configuration (of `vm_configuration_size`) can be retrieved using +[`proxy_get_buffer_bytes`] with `buffer_id` set to `VM_CONFIGURATION`. + +Plugin must return one of the following values: +- `true` to indicate that the configuration was processed successfully. +- `false` to indicate that the configuration processing failed. + + +#### `proxy_on_configure` + +* params: + - `i32 (uint32_t) plugin_context_id` + - `i32 (size_t) plugin_configuration_size` +* returns: + - `i32 (bool) status` + +Called when the host starts the Proxy-Wasm plugin. + +Its configuration (of `plugin_configuration_size`) can be retrieved +using [`proxy_get_buffer_bytes`] with `buffer_id` set to +`PLUGIN_CONFIGURATION`. + +Plugin must return one of the following values: +- `true` to indicate that the configuration was processed successfully. +- `false` to indicate that the configuration processing failed. + + +## Logging + +### Functions exposed by the host + +#### `proxy_log` + +* params: + - `i32 (`[`proxy_log_level_t`]`) log_level` + - `i32 (const char *) message_data` + - `i32 (size_t) message_size` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Logs message (`message_data`, `message_size`) at the `log_level`. + +Returned `status` value is: +- `OK` on success. +- `BAD_ARGUMENT` for unknown `log_level`. +- `INVALID_MEMORY_ACCESS` when `message_data` and/or `message_size` + point to invalid memory address. + + +#### `wasi_snapshot_preview1.fd_write` + +* params: + - `i32 (`[`wasi_fd_id_t`]`) fd_id` + - `i32 (wasi_iovec_array_t) iovec` + - `i32 (size_t) iovec_size` + - `i32 (size_t *) return_written_bytes` +* returns: + - `i32 (`[`wasi_errno_t`]`) errno` + +Logs message (`iovec`, `iovec_size`). + +When `fd_id` is `STDOUT`, then it's logged at the `INFO` level. + +When `fd_id` is `STDERR`, then it's logged at the `ERROR` level. + +Returned `errno` value is: +- `SUCCESS` on success. +- `BADF` for unknown or unsupported `fd_id`. +- `FAULT` when `iovec`, `iovec_size` and/or `return_written_bytes` + point to invalid memory address. + + +#### `proxy_get_log_level` + +* params: + - `i32 (`[`proxy_log_level_t`]` *) return_log_level` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Retrieves host's current log level (`return_log_level`). + +This can be used to avoid creating log entries that are going to be +discarded by the host. + +Returned `status` value is: +- `OK` on success. +- `INVALID_MEMORY_ACCESS` when `return_log_level` points to invalid + memory address. + + +## Clocks + +### Functions exposed by the host + +#### `proxy_get_current_time_nanoseconds` + +* params: + - `i32 (uint64_t *) return_time` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +> **Warning** +> This function has been deprecated in favor of +> [`wasi_snapshot_preview1.clock_time_get`]. + +Retrieves current time (`return_time`), or the approximation of it. + +> **Note** +> Hosts might return approximate time (e.g. frozen at the context +> creation) to improve performance and/or prevent various attacks, +> so consumers shouldn't assume that time changes during callbacks. + +Returned `status` value is: +- `OK` on success. +- `INVALID_MEMORY_ACCESS` when `return_time` points to invalid memory + address. + + +#### `wasi_snapshot_preview1.clock_time_get` + +* params: + - `i32 (`[`wasi_clock_id_t`]`) clock_id` + - `i64 (uint64_t) ignored` + - `i32 (uint64_t *) return_time` +* returns: + - `i32 (`[`wasi_errno_t`]`) errno` + +Retrieves current time (`return_time`), or the approximation of it. + +> **Note** +> Hosts might return approximate time (e.g. frozen at the context +> creation) to improve performance and/or prevent various attacks, +> so consumers shouldn't assume that time changes during callbacks. + +Returned `errno` value is: +- `SUCCESS` on success. +- `NOTSUP` for unknown or unsupported `clock_id`. +- `FAULT` when `return_time` points to invalid memory address. + + +## Timers + +### Functions exposed by the host + +#### `proxy_set_tick_period_milliseconds` + +* params: + - `i32 (uint32_t) tick_period` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Sets timer period (`tick_period`). When set, the host will call +[`proxy_on_tick`] every `tick_period` milliseconds. + +Returned `status` value is: +- `OK` on success. + + +### Callbacks exposed by the Wasm module + +#### `proxy_on_tick` + +* params: + - `i32 (uint32_t) plugin_context_id` +* returns: + - none + +Called on a timer every tick period. + +The tick period can be configured using +[`proxy_set_tick_period_milliseconds`]. + + +## Randomness + +### Functions exposed by the host + +#### `wasi_snapshot_preview1.random_get` + +* params: + - `i32 (uint8_t *) buffer` + - `i32 (size_t) buffer_size` +* returns: + - `i32 (`[`wasi_errno_t`]`) errno` + +Generates `buffer_size` bytes of randomness. + +Returned `errno` value is: +- `SUCCESS` on success. +- `INVAL` when requested `buffer_size` is too large. +- `FAULT` when `buffer` and/or `buffer_size` point to invalid memory + address. + + +## Environment variables + +> **Warning** +> Environment variables should be configured for each plugin. +> Exposing the host's environment variables is highly discouraged. + + +### Functions exposed by the host + +#### `wasi_snapshot_preview1.environ_sizes_get` + +* params: + - `i32 (size_t *) return_num_elements` + - `i32 (size_t *) return_buffer_size` +* returns: + - `i32 (`[`wasi_errno_t`]`) errno` + +Returns `return_num_elements` of environment variables, and +`return_buffer_size` sufficient to serialize them and decorators. + +Returned `errno` value is: +- `SUCCESS` on success. +- `FAULT` when `return_num_elements` and/or `return_buffer_size` + point to invalid memory address. + + +#### `wasi_snapshot_preview1.environ_get` + +* params: + - `i32 (uint8_t **) return_array` + - `i32 (uint8_t *) return_buffer` +* returns: + - `i32 (`[`wasi_errno_t`]`) errno` + +Returns serialized environment variables. + +Returned `errno` value is: +- `SUCCESS` on success. +- `FAULT` when `return_array` and/or `return_buffer` point to + invalid memory address. + + +## Buffers + +Access to buffers using functions in this section is restricted to +specific callbacks: + +- `HTTP_REQUEST_BODY` can be read and modified in + [`proxy_on_request_body`] (or for as long as request processing + is paused from it). +- `HTTP_RESPONSE_BODY` can be read and modified in + [`proxy_on_response_body`] (or for as long as response processing + is paused from it). +- `DOWNSTREAM_DATA` can be read and modified in + [`proxy_on_downstream_data`] (or for as long as upstream processing + is paused from it). +- `UPSTREAM_DATA` can be read and modified in + [`proxy_on_downstream_data`] (or for as long as downstream processing + is paused from it). +- `HTTP_CALL_RESPONSE_BODY` can be read in + [`proxy_on_http_call_response`]. +- `GRPC_CALL_MESSAGE` can be read in [`proxy_on_grpc_receive`]. +- `VM_CONFIGURATION` can be read in [`proxy_on_vm_start`]. +- `PLUGIN_CONFIGURATION` can be read in [`proxy_on_configure`]. +- `FOREIGN_FUNCTION_ARGUMENTS` can be read in + [`proxy_on_foreign_function`]. + + +### Functions exposed by the host + +#### `proxy_set_buffer_bytes` + +* params: + - `i32 (`[`proxy_buffer_type_t`]`) buffer_id` + - `i32 (uint32_t) offset` + - `i32 (uint32_t) size` + - `i32 (const uint8_t *) value_data` + - `i32 (size_t) value_size` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Sets content of the buffer `buffer_id` to the provided value +(`value_data`, `value_size`) replacing `size` bytes starting +at `offset` in the existing buffer. + +Returned `status` value is: +- `OK` on success. +- `BAD_ARGUMENT` for unknown `buffer_id`. +- `NOT_FOUND` when requested `buffer_id` isn't available. +- `INVALID_MEMORY_ACCESS` when `value_data` and/or `value_size` + point to invalid memory address. + + +#### `proxy_get_buffer_bytes` + +* params: + - `i32 (`[`proxy_buffer_type_t`]`) buffer_id` + - `i32 (uint32_t) offset` + - `i32 (uint32_t) max_size` + - `i32 (uint8_t **) return_value_data` + - `i32 (size_t *) return_value_size` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Retrieves up to` max_size` bytes starting at `offset` from the buffer +`buffer_id`. + +Returned `status` value is: +- `OK` on success. +- `BAD_ARGUMENT` for unknown `buffer_id`, or in case of buffer overflow + due to invalid `offset` and/or `max_size` values. +- `NOT_FOUND` when requested `buffer_id` isn't available. +- `INVALID_MEMORY_ACCESS` when `returned_value_data` and/or + `returned_value_size` point to invalid memory address. + + +#### `proxy_get_buffer_status` + +* params: + - `i32 (`[`proxy_buffer_type_t`]`) buffer_id` + - `i32 (size_t *) return_buffer_size` + - `i32 (uint32_t *) return_ignored` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Retrieves size (`return_buffer_size`) of the buffer `buffer_id`. + +Returned `status` value is: +- `OK` on success. +- `BAD_ARGUMENT` for unknown `buffer_id`. +- `NOT_FOUND` when requested `buffer_id` isn't available. +- `INVALID_MEMORY_ACCESS` when `return_buffer_size` and/or + `return_ignored` point to invalid memory address. + + +## HTTP fields + +Access to HTTP fields using functions in this section is restricted to +specific callbacks: + +- `HTTP_REQUEST_HEADERS` can be read in [`proxy_on_log`], + and read and modified from [`proxy_on_request_headers`] + (or for as long as request processing is paused from it). +- `HTTP_REQUEST_TRAILERS` can be read in [`proxy_on_log`], + and read and modified in [`proxy_on_request_trailers`] + (or for as long as request processing is paused from it). + They can be added in [`proxy_on_request_body`], but only when the + proxied request doesn't have trailers (`end_of_stream` is `true`). +- `HTTP_RESPONSE_HEADERS` can be read in [`proxy_on_log`], + and read and modified in [`proxy_on_response_headers`] + (or for as long as response processing is paused from it). +- `HTTP_RESPONSE_TRAILERS` can be read in [`proxy_on_log`], + and read and modified in [`proxy_on_response_trailers`] + (or for as long as response processing is paused from it). + They can be added in [`proxy_on_response_body`], but only when the + proxied response doesn't have trailers (`end_of_stream` is `true`). +- `GRPC_CALL_INITIAL_METADATA` can be read in + [`proxy_on_grpc_receive_initial_metadata`]. +- `GRPC_CALL_TRAILING_METADATA` can be read in + [`proxy_on_grpc_receive_trailing_metadata`]. +- `HTTP_CALL_RESPONSE_HEADERS` can be read in + [`proxy_on_http_call_response`]. +- `HTTP_CALL_RESPONSE_TRAILERS` can be read in + [`proxy_on_http_call_response`]. + + +### Functions exposed by the host + +#### `proxy_get_header_map_size` + +* params: + - `i32 (`[`proxy_header_map_type_t`]`) map_id` + - `i32 (size_t *) return_pairs_size` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Retrieves size (`return_pairs_size`) of all key-value pairs from +the header map `map_id`. + +Returned `status` value is: +- `OK` on success. +- `BAD_ARGUMENT` for unknown `map_id`. +- `INVALID_MEMORY_ACCESS` when `return_pairs_size` points to + invalid memory address. + + +#### `proxy_get_header_map_pairs` + +* params: + - `i32 (`[`proxy_header_map_type_t`]`) map_id` + - `i32 (uint8_t **) return_serialized_pairs_data` + - `i32 (size_t *) return_serialized_pairs_size` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Retrieves all key-value pairs from the header map `map_id`. + +Returned header map (`return_serialized_pairs_data`, +`return_serialized_pairs_size`) is [serialized]. + +Returned `status` value is: +- `OK` on success. +- `BAD_ARGUMENT` for unknown `map_id`. +- `INVALID_MEMORY_ACCESS` when `return_pairs_data` and/or + `return_pairs_size` point to invalid memory address. + + +#### `proxy_set_header_map_pairs` + +* params: + - `i32 (`[`proxy_header_map_type_t`]`) map_id` + - `i32 (const uint8_t *) serialized_pairs_data` + - `i32 (size_t) serialized_pairs_size` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Sets all key-value pairs in the header map `map_id` to the provided +[serialized] map (`serialized_pairs_data`, `serialized_pairs_size`). + +Returned `status` value is: +- `OK` on success. +- `BAD_ARGUMENT` for unknown `map_id`. +- `INVALID_MEMORY_ACCESS` when `pairs_data` and/or + `pairs_size` point to invalid memory address. + + +#### `proxy_get_header_map_value` + +* params: + - `i32 (`[`proxy_header_map_type_t`]`) map_id` + - `i32 (const char *) key_data` + - `i32 (size_t) key_size` + - `i32 (uint8_t **) return_value_data` + - `i32 (size_t *) return_value_size` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Retrieves value (`return_value_data`, `return_value_size`) of the header +key (`key_data`, `key_value`) from the header map `map_id`. + +Returned `status` value is: +- `OK` on success. +- `BAD_ARGUMENT` for unknown `map_id`. +- `NOT_FOUND` when the requested key was not found. +- `INVALID_MEMORY_ACCESS` when `key_data`, `key_size`, + `return_value_data` and/or `return_value_size` point to + invalid memory address. + + +#### `proxy_add_header_map_value` + +* params: + - `i32 (`[`proxy_header_map_type_t`]`) map_id` + - `i32 (const char *) key_data` + - `i32 (size_t) key_size` + - `i32 (const uint8_t *) value_data` + - `i32 (size_t) value_size` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Adds key (`key_data`, `key_size`) with value (`value_data`, +`value_size`) to the header map `map_id`. + +Returned `status` value is: +- `OK` on success. +- `BAD_ARGUMENT` for unknown `map_id`. +- `INVALID_MEMORY_ACCESS` when `key_data`, `key_size`, `value_data` + and/or `value_size` point to invalid memory address. + + +#### `proxy_replace_header_map_value` + +* params: + - `i32 (`[`proxy_header_map_type_t`]`) map_id` + - `i32 (const char *) key_data` + - `i32 (size_t) key_size` + - `i32 (const uint8_t *) value_data` + - `i32 (size_t) value_size` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Adds or replaces key's (`key_data`, `key_value`) value with the provided +value (`value_data`, `value_size`) in the header map `map_id`. + +Returned `status` value is: +- `OK` on success. +- `BAD_ARGUMENT` for unknown `map_id`. +- `INVALID_MEMORY_ACCESS` when `key_data`, `key_size`, `value_data` + and/or `value_size` point to invalid memory address. + + +#### `proxy_remove_header_map_value` + +* params: + - `i32 (`[`proxy_header_map_type_t`]`) map_id` + - `i32 (const char *) key_data` + - `i32 (size_t) key_size` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Removes the key (`key_data`, `key_value`) from the header map `map_id`. + +Returned `status` value is: +- `OK` on success (including the case when requested key didn't exist). +- `BAD_ARGUMENT` for unknown `map_id`. +- `INVALID_MEMORY_ACCESS` when `key_data` and/or `key_size` point to + invalid memory address. + + +## Common stream operations + +### Functions exposed by the host + +#### `proxy_continue_stream` + +* params: + - `i32 (`[`proxy_stream_type_t`]`) stream_type` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Resumes processing of paused `stream_type`. + +Returned `status` value is: +- `OK` on success. +- `BAD_ARGUMENT` for unknown `stream_type`. +- `UNIMPLEMENTED` when continuation of requested `stream_type` + is not supported. + + +#### `proxy_close_stream` + +* params: + - `i32 (`[`proxy_stream_type_t`]`) stream_type` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Closes or resets `stream_type`. + +Returned `status` value is: +- `OK` on success. +- `BAD_ARGUMENT` for unknown `stream_type`. + + +#### `proxy_get_status` + +* params: + - `i32 (uint32_t *) return_status_code` + - `i32 (const char **) return_status_message_data` + - `i32 (size_t *) return_status_message_size` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Retrieves status code (`return_status_code`) and status message +(`return_status_message_data`, `return_status_message_size`) of +the HTTP call when called from [`proxy_on_http_call_response`] +or gRPC stream or call when called from [`proxy_on_grpc_close`]. + +Returned `status` value is: +- `OK` on success. +- `INVALID_MEMORY_ACCESS` when `return_status_code`, + `return_status_message_data` and/or `return_status_message_size` + point to invalid memory address. + + +## TCP/UDP/QUIC streams + +> **Note** +> `downstream` refers to the connection between client and proxy, +> `upstream` refers to the connection between proxy and backend. + + +### Callbacks exposed by the Wasm module + +> **Note** +> The same unique `stream_context_id` is shared by +> a pair of `downstream` and `upstream` connections. + + +#### `proxy_on_new_connection` + +* params: + - `i32 (uint32_t) stream_context_id` +* returns: + - `i32 (`[`proxy_action_t`]`) action` + +Called when a new connection is established. + +Plugin must return one of the following values: +- `CONTINUE` to allow the new connection to be established. +- `PAUSE` to pause processing of the new connection. + + +#### `proxy_on_downstream_data` + +* params: + - `i32 (uint32_t) stream_context_id` + - `i32 (size_t) data_size` + - `i32 (bool) end_of_stream` +* returns: + - `i32 (`[`proxy_action_t`]`) action` + +Called for each data chunk received from downstream, +even when the processing is paused. + +`data_size` represents total available size of the data that can be +retrieved, and its value will increment if the processing is paused +and data is buffered by the host and not forwarded upstream. + +Data (of `data_size`) can be retrieved and/or modified using +[`proxy_get_buffer_bytes`] and/or [`proxy_set_buffer_bytes`] +with `buffer_id` set to `DOWNSTREAM_DATA`. + +Paused downstream can be resumed using [`proxy_continue_stream`] +or closed using [`proxy_close_stream`] with `stream_type` set to +`DOWNSTREAM`. + +Plugin must return one of the following values: +- `CONTINUE` to forward `DOWNSTREAM_DATA` buffer upstream. +- `PAUSE` to pause processing. + + +#### `proxy_on_downstream_connection_close` + +* params: + - `i32 (uint32_t) stream_context_id` + - `i32 (`[`proxy_peer_type_t`]`) peer_type` +* returns: + - none + +Called when downstream connection is closed. + + +#### `proxy_on_upstream_data` + +* params: + - `i32 (uint32_t) stream_context_id` + - `i32 (size_t) data_size` + - `i32 (bool) end_of_stream` +* returns: + - `i32 (`[`proxy_action_t`]`) action` + +Called for each data chunk received from upstream, +even when the processing is paused. + +`data_size` represents total available size of the data that can be +retrieved, and its value will increment if the processing is paused +and data is buffered by the host and not forwarded downstream. + +Data (of `data_size`) can be retrieved and/or modified using +[`proxy_get_buffer_bytes`] and/or [`proxy_set_buffer_bytes`] +with `buffer_id` set to `UPSTREAM_DATA`. + +Paused upstream can be resumed using [`proxy_continue_stream`] +or closed using [`proxy_close_stream`] with `stream_type` set to +`UPSTREAM`. + +Plugin must return one of the following values: +- `CONTINUE` to forward `UPSTREAM_DATA` buffer downstream. +- `PAUSE` to pause processing. + + +#### `proxy_on_upstream_connection_close` + +* params: + - `i32 (uint32_t) stream_context_id` + - `i32 (`[`proxy_peer_type_t`]`) peer_type` +* returns: + - none + +Called when upstream connection is closed. + + +## HTTP + +### Callbacks exposed by the Wasm module + +> **Note** +> The same unique `stream_context_id` is shared by +> HTTP request and response. + +#### `proxy_on_request_headers` + +* params: + - `i32 (uint32_t) stream_context_id` + - `i32 (size_t) num_headers` + - `i32 (bool) end_of_stream` +* returns: + - `i32 (`[`proxy_action_t`]`) action` + +Called when HTTP request headers are received from downstream. + +All `num_headers` headers can be retrieved and/or modified using +[`proxy_get_header_map_pairs`] and/or [`proxy_set_header_map_pairs`] +with `map_id` set to `HTTP_REQUEST_HEADERS`. + +Individual HTTP request headers can be retrieved and/or modified using +[`proxy_get_header_map_value`], [`proxy_replace_header_map_value`], +[`proxy_add_header_map_value`] and/or [`proxy_remove_header_map_value`] +with `map_id` set to `HTTP_REQUEST_HEADERS`. + +Paused request can be resumed using [`proxy_continue_stream`] +or closed using [`proxy_close_stream`] with `stream_type` set to +`HTTP_REQUEST`. + +Additionally, instead of forwarding request upstream, a HTTP response +can be sent using [`proxy_send_local_response`]. + +Plugin must return one of the following values: +- `CONTINUE` to forward `HTTP_REQUEST_HEADERS` fields downstream. +- `PAUSE` to pause processing. + + +#### `proxy_on_request_body` + +* params: + - `i32 (uint32_t) stream_context_id` + - `i32 (size_t) body_size` + - `i32 (bool) end_of_stream` +* returns: + - `i32 (`[`proxy_action_t`]`) action` + +Called for each chunk of HTTP request body received from downstream, +even when the processing is paused. + +Request body chunk (of `body_size`) can be retrieved and/or modified +using [`proxy_get_buffer_bytes`] and/or [`proxy_set_buffer_bytes`] +with `buffer_id` set to `HTTP_REQUEST_BODY`. + +`body_size` represents total available size of the body that can be +retrieved, and its value will increment if the processing is paused +and the body is buffered by the host and not forwarded upstream. + +Paused HTTP request can be resumed using [`proxy_continue_stream`] +or closed using [`proxy_close_stream`] with `stream_type` set to +`HTTP_REQUEST`. + +Additionally, as long as HTTP response headers were not send downstream, +a HTTP response can be sent using [`proxy_send_local_response`]. + +Plugin must return one of the following values: +- `CONTINUE` to forward `HTTP_REQUEST_BODY` buffer upstream. +- `PAUSE` to pause processing. + + +#### `proxy_on_request_trailers` + +* params: + - `i32 (uint32_t) stream_context_id` + - `i32 (size_t) num_trailers` +* returns: + - `i32 (`[`proxy_action_t`]`) action` + +Called when HTTP request trailers are received from downstream. + +All `num_trailers` trailers can be retrieved and/or modified using +[`proxy_get_header_map_pairs`] and/or [`proxy_set_header_map_pairs`] +with `map_id` set to `HTTP_REQUEST_TRAILERS`. + +Individual HTTP request trailers can be retrieved and/or modified using +[`proxy_get_header_map_value`], [`proxy_replace_header_map_value`], +[`proxy_add_header_map_value`] and/or [`proxy_remove_header_map_value`] +with `map_id` set to `HTTP_REQUEST_TRAILERS`. + +Paused request can be resumed using [`proxy_continue_stream`] +or closed using [`proxy_close_stream`] with `stream_type` set to +`HTTP_REQUEST`. + +Additionally, as long as HTTP response headers were not send downstream, +a HTTP response can be sent using [`proxy_send_local_response`]. + +Plugin must return one of the following values: +- `CONTINUE` to forward `HTTP_REQUEST_TRAILERS` fields downstream. +- `PAUSE` to pause processing. + + +#### `proxy_on_response_headers` + +* params: + - `i32 (uint32_t) stream_context_id` + - `i32 (size_t) num_headers` + - `i32 (bool) end_of_stream` +* returns: + - `i32 (`[`proxy_action_t`]`) action` + +Called when HTTP response headers are received from upstream. + +All `num_headers` headers can be retrieved and/or modified using +[`proxy_get_header_map_pairs`] and/or [`proxy_set_header_map_pairs`] +with `map_id` set to `HTTP_RESPONSE_HEADERS`. + +Individual headers can be retrieved and/or modified using +[`proxy_get_header_map_value`], [`proxy_replace_header_map_value`], +[`proxy_add_header_map_value`] and/or [`proxy_remove_header_map_value`] +with `map_id` set to `HTTP_RESPONSE_HEADERS`. + +Paused request can be resumed using [`proxy_continue_stream`] +or closed using [`proxy_close_stream`] with `stream_type` set to +`HTTP_RESPONSE`. + +Additionally, instead of forwarding the response from upstream, +a new HTTP response can be sent using [`proxy_send_local_response`]. + +Plugin must return one of the following values: +- `CONTINUE` to forward `HTTP_RESPONSE_HEADERS` fields downstream. +- `PAUSE` to pause processing. + + +#### `proxy_on_response_body` + +* params: + - `i32 (uint32_t) stream_context_id` + - `i32 (size_t) body_size` + - `i32 (bool) end_of_stream` +* returns: + - `i32 (`[`proxy_action_t`]`) action` + +Called for each chunk of HTTP response body received from upstream, +even when the processing is paused. + +Response body chunk (of `body_size`) can be retrieved and/or modified +using [`proxy_get_buffer_bytes`] and/or [`proxy_set_buffer_bytes`] +with `buffer_id` set to `HTTP_RESPONSE_BODY`. + +`body_size` represents total available size of the body that can be +retrieved, and its value will increment if the processing is paused +and the body is buffered by the host and not forwarded downstream. + +Paused HTTP response can be resumed using [`proxy_continue_stream`] +or closed using [`proxy_close_stream`] with `stream_type` set to +`HTTP_RESPONSE`. + +Plugin must return one of the following values: +- `CONTINUE` to forward `HTTP_RESPONSE_BODY` buffer downstream. +- `PAUSE` to pause processing. + + +#### `proxy_on_response_trailers` + +* params: + - `i32 (uint32_t) stream_context_id` + - `i32 (size_t) num_trailers` +* returns: + - `i32 (`[`proxy_action_t`]`) action` + +Called when HTTP response trailers are received from upstream. + +All `num_trailers` trailers can be retrieved and/or modified using +[`proxy_get_header_map_pairs`] and/or [`proxy_set_header_map_pairs`] +with `map_id` set to `HTTP_RESPONSE_TRAILERS`. + +Individual trailers can be retrieved and/or modified using +[`proxy_get_header_map_value`], [`proxy_replace_header_map_value`], +[`proxy_add_header_map_value`] and/or [`proxy_remove_header_map_value`] +with `map_id` set to `HTTP_RESPONSE_TRAILERS`. + +Paused request can be resumed using [`proxy_continue_stream`] +or closed using [`proxy_close_stream`] with `stream_type` set to +`HTTP_REQUEST`. + +Plugin must return one of the following values: +- `CONTINUE` to forward `HTTP_RESPONSE_TRAILERS` fields downstream. +- `PAUSE` to pause processing. + + +### Functions exposed by the host + +#### `proxy_send_local_response` + +* params: + - `i32 (uint32_t) status_code` + - `i32 (const char *) status_code_details_data` + - `i32 (size_t) status_code_details_size` + - `i32 (const uint8_t *) body_data` + - `i32 (size_t) body_size` + - `i32 (const uint8_t *) serialized_headers_data` + - `i32 (size_t) serialized_headers_size` + - `i32 (uint32_t) grpc_status` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Sends HTTP response with body (`body_data`, `body_size`) and +[serialized] headers (`serialized_headers_data`, +`serialized_headers_size`). + +This can be used as long as HTTP response headers were not send +downstream. + +Returned `status` value is: +- `OK` on success. +- `INVALID_MEMORY_ACCESS` when `status_code_details_data`, + `status_code_details_size`, `body_data`, `body_size`, `headers_data` + and/or `headers_size` point to invalid memory address. + + +## HTTP calls + +### Functions exposed by the host + +#### `proxy_http_call` + +* params: + - `i32 (const char *) upstream_name_data` + - `i32 (size_t) upstream_name_size` + - `i32 (const uint8_t *) serialized_headers_data` + - `i32 (size_t) serialized_headers_size` + - `i32 (const uint8_t *) body_data` + - `i32 (size_t) body_size` + - `i32 (const uint8_t *) serialized_trailers_data` + - `i32 (size_t) serialized_trailers_size` + - `i32 (uint32_t) timeout` + - `i32 (uint32_t *) return_call_id` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Sends HTTP request with [serialized] headers (`serialized_headers_data`, +`serialized_headers_size`), `body`, and [serialized] trailers +(`serialized_trailers_data`, `serialized_trailers_size`) +to upstream (`upstream_name_data`, `upstream_name_size`). + +[`proxy_on_http_call_response`] will be called with `return_call_id` +when the response is received by the host, or after the `timeout`. + +Returned `status` value is: +- `OK` on success. +- `BAD_ARGUMENT` for unknown `upstream`, or when `headers` are missing + required `:authority`, `:method` and/or `:path` values. +- `INTERNAL_FAILURE` when the host failed to send requested HTTP call. +- `INVALID_MEMORY_ACCESS` when `upstream_data`, `upstream_size`, + `headers_data`, `headers_size` `body_data`, `body_size`, + `trailers_data`, `trailers_size` and/or `return_call_id` point to + invalid memory address. + + +### Callbacks exposed by the Wasm module + +#### `proxy_on_http_call_response` + +* params: + - `i32 (uint32_t) plugin_context_id` + - `i32 (uint32_t) call_id` + - `i32 (size_t) num_headers` + - `i32 (size_t) body_size` + - `i32 (size_t) num_trailers` +* returns: + - none + +Called when HTTP response for `call_id` sent using +[`proxy_http_call`] is received. + +If `num_headers` is `0`, then the HTTP call failed. + +All `num_headers` headers can be retrieved using +[`proxy_get_header_map_pairs`] +or individually [`proxy_get_header_map_value`] +with `map_id` set to `HTTP_CALL_RESPONSE_HEADERS`. + +Response body (of `body_size`) can be retrieved using +[`proxy_get_buffer_bytes`] with `buffer_id` set to +`HTTP_RESPONSE_BODY`. + +All `num_trailers` trailers can be retrieved using +[`proxy_get_header_map_pairs`] +or individually [`proxy_get_header_map_value`] +with `map_id` set to `HTTP_CALL_RESPONSE_TRAILERS`. + + +## gRPC calls + +### Functions exposed by the host + +#### `proxy_grpc_call` + +* params: + - `i32 (const char *) upstream_name_data` + - `i32 (size_t) upstream_name_size` + - `i32 (const char *) service_name_data` + - `i32 (size_t) service_name_size` + - `i32 (const char *) method_name_data` + - `i32 (size_t) method_name_size` + - `i32 (const uint8_t *) serialized_initial_metadata_data` + - `i32 (size_t) serialized_initial_metadata_size` + - `i32 (const uint8_t *) message_data` + - `i32 (size_t) message_size` + - `i32 (uint32_t) timeout` + - `i32 (uint32_t *) return_call_id` + * returns: + - `i32 (`[`proxy_status_t`]`) status` + +Sends gRPC message (`message_data`, `message_size`) with [serialized] +initial metadata (`serialized_initial_metadata_data`, +`serialized_initial_metadata_size`) +to gRPC method (`method_name_data`, `method_name_size`) +on gRPC service (`service_name_data`, `service_name_size`) +on upstream (`upstream_name_data`, `upstream_name_size`). + +[`proxy_on_grpc_receive`] or [`proxy_on_grpc_close`] will be called +with `return_call_id` when the response is received by the host, or +after the `timeout`. + +`return_call_id` can also be used to cancel the outstanding request +using [`proxy_grpc_cancel`] or close it using [`proxy_grpc_close`]. + +Returned `status` value is: +- `OK` on success. +- `PARSE_FAILURE` for unknown `upstream`. +- `INTERNAL_FAILURE` when the host failed to send a gRPC call. +- `INVALID_MEMORY_ACCESS` when `upstream_data`, `upstream_size`, + `service_name_data`, `service_name_size` `method_name_data`, + `method_name_size`, `initial_metadata_data`, `initial_metadata_size`, + `message_data`, `message_size` and/or `return_call_id` point to + invalid memory address. + + +#### `proxy_grpc_stream` + +* params: + - `i32 (const char *) upstream_name_data` + - `i32 (size_t) upstream_name_size` + - `i32 (const char *) service_name_data` + - `i32 (size_t) service_name_size` + - `i32 (const char *) method_name_data` + - `i32 (size_t) method_name_size` + - `i32 (const uint8_t *) serialized_initial_metadata_data` + - `i32 (size_t) serialized_initial_metadata_size` + - `i32 (uint32_t *) return_stream_id` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Opens gRPC stream with [serialized] initial metadata +(`serialized_initial_metadata_data`, `serialized_initial_metadata_size`) +to gRPC method (`method_name_data`, `method_name_size`) +on gRPC service (`service_name_data`, `service_name_size`) +on upstream (`upstream_name_data`, `upstream_name_size`). + +gRPC messages can be sent on this stream using [`proxy_grpc_send`] +with `return_stream_id`. + +[`proxy_on_grpc_receive`] or [`proxy_on_grpc_close`] will be called +with `return_stream_id` when the response is received by the host, +or after the `timeout`. + +`return_stream_id` can also be used to cancel outstanding gRPC messages +using [`proxy_grpc_cancel`] or close this gRPC stream using +[`proxy_grpc_close`]. + +Returned `status` value is: +- `OK` on success. +- `PARSE_FAILURE` for unknown `upstream`. +- `INTERNAL_FAILURE` when the host failed to open gRPC stream. +- `INVALID_MEMORY_ACCESS` when `upstream_data`, `upstream_size`, + `service_name_data`, `service_name_size` `method_name_data`, + `method_name_size`, `initial_metadata_data`, `initial_metadata_size` + and/or `return_stream_id` point to invalid memory address. + + +#### `proxy_grpc_send` + +* params: + - `i32 (uint32_t) stream_id` + - `i32 (const uint8_t *) message_data` + - `i32 (size_t) message_size` + - `i32 (bool) end_stream` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Sends gRPC message (`message_data`, `message_size`) on the gRPC stream +`stream_id` previously established using [`proxy_grpc_stream`]. + +Returned `status` value is: +- `OK` on success. +- `BAD_ARGUMENT` for invalid `stream_id`. +- `NOT_FOUND` for unknown `stream_id`. +- `INVALID_MEMORY_ACCESS` when `message_data` and/or `message_size` + point to invalid memory address. + + +#### `proxy_grpc_cancel` + +* params: + - `i32 (uint32_t) call_or_stream_id` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Cancels `call_or_stream_id` previously started using +[`proxy_grpc_call`] or [`proxy_grpc_stream`]. + +Returned `status` value is: +- `OK` on success. +- `BAD_ARGUMENT` for invalid `call_or_stream_id`. +- `NOT_FOUND` for unknown `call_or_stream_id`. + + +#### `proxy_grpc_close` + +* params: + - `i32 (uint32_t) call_or_stream_id` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Closes `call_or_stream_id` previously started using +[`proxy_grpc_call`] or [`proxy_grpc_stream`]. + +Returned `status` value is: +- `OK` on success. +- `BAD_ARGUMENT` for invalid `call_or_stream_id`. +- `NOT_FOUND` for unknown `call_or_stream_id`. + + +### Callbacks exposed by the Wasm module + +#### `proxy_on_grpc_receive_initial_metadata` + +* params: + - `i32 (uint32_t) plugin_context_id` + - `i32 (uint32_t) call_id` + - `i32 (size_t) num_elements` +* returns: + - none + +Called when initial gRPC metadata for `call_id` opened using +[`proxy_grpc_call`] or [`proxy_grpc_stream`] is received. + +All `num_elements` elements can be retrieved using +[`proxy_get_header_map_pairs`] or individually +[`proxy_get_header_map_value`] with `map_id` set to +`GRPC_CALL_INITIAL_METADATA`. + + +#### `proxy_on_grpc_receive` + +* params: + - `i32 (uint32_t) plugin_context_id` + - `i32 (uint32_t) call_id` + - `i32 (size_t) message_size` +* returns: + - none + +Called when the response gRPC message for `call_id` sent using +[`proxy_grpc_call`] or [`proxy_grpc_send`] is received. + +Message (of `message_size`) can be retrieved using +[`proxy_get_buffer_bytes`] with `buffer_id` set to `GRPC_CALL_MESSAGE`. + + +#### `proxy_on_grpc_receive_trailing_metadata` + +* params: + - `i32 (uint32_t) plugin_context_id` + - `i32 (uint32_t) call_id` + - `i32 (size_t) num_elements` +* returns: + - none + +Called when trailing gRPC metadata for `call_id` opened using +[`proxy_grpc_call`] or [`proxy_grpc_stream`] is received. + +All `num_elements` elements can be retrieved using +[`proxy_get_header_map_pairs`] or individually +[`proxy_get_header_map_value`] with `map_id` set to +`GRPC_CALL_TRAILING_METADATA`. + + +#### `proxy_on_grpc_close` + +* params: + - `i32 (uint32_t) plugin_context_id` + - `i32 (uint32_t) call_id` + - `i32 (uint32_t) status_code` +* returns: + - none + +Called when gRPC call or stream `call_id` opened using +[`proxy_grpc_call`] or [`proxy_grpc_stream`] is received. + +gRPC status message can be retrieved using [`proxy_get_status`]. + + +## Shared Key-Value Store + +### Functions exposed by the host + +#### `proxy_set_shared_data` + +* params: + - `i32 (const char *) key_data` + - `i32 (size_t) key_size` + - `i32 (const uint8_t *) value_data` + - `i32 (size_t) value_size` + - `i32 (uint32_t) cas` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Sets shared data identified by the key (`key_data`, `key_value`) +to the value (`value_data`, `value_size`). + +If the compare-and-swap value (`cas`) is set to a non-zero value, +then it must match the host's compare-and-swap value in order for +the update to succeed. + +Returned `status` value is: +- `OK` on success. +- `CAS_MISMATCH` when `cas` doesn't match host's compare-and-swap + value. +- `INVALID_MEMORY_ACCESS` when `key_data`, `key_size`, `value_data`, + `value_size` and/or `cas` point to invalid memory address. + + +#### `proxy_get_shared_data` + +* params: + - `i32 (const char *) key_data` + - `i32 (size_t) key_size` + - `i32 (uint8_t **) return_value_data` + - `i32 (size_t *) return_value_size` + - `i32 (uint32_t *) return_cas` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Returns shared value (`return_value`) identified by the key (`key_data`, +`key_value`). + +The compare-and-swap value (`return_cas`) can be used for atomically +updating this value using [`proxy_set_shared_data`]. + +Returned `status` value is: +- `OK` on success. +- `NOT_FOUND` when the requested key was not found. +- `INVALID_MEMORY_ACCESS` when `key_data`, `key_size`, + `return_value_data`, `return_value_size` and/or `return_cas` + point to invalid memory address. + + +## Shared Queues + +### Functions exposed by the host + +#### `proxy_register_shared_queue` + +* params: + - `i32 (const char *) name_data` + - `i32 (size_t) name_size` + - `i32 (uint32_t *) return_queue_id` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Registers shared queue under a name (`name_data`, `name_size`). + +If the named queue already exists, then it's going to be opened +instead of creating a new empty queue. + +Items can be enqueued/dequeued on the created/opened queue using +[`proxy_enqueue_shared_queue`] and/or [`proxy_dequeue_shared_queue`] +with `return_queue_id`. + +Returned `status` value is: +- `OK` on success. +- `INVALID_MEMORY_ACCESS` when `name_data`, `name_size` + and/or `return_queue_id` point to invalid memory address. + + +#### `proxy_resolve_shared_queue` + +* params: + - `i32 (const char *) vm_id_data` + - `i32 (size_t) vm_id_size` + - `i32 (const char *) name_data` + - `i32 (size_t) name_size` + - `i32 (uint32_t *) return_queue_id` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Resolves existing shared queue using the provided VM ID (`vm_id_data`, +`vm_id_size`) and name (`name_data`, `name_size`). + +Items can be enqueued/dequeued on the opened queue using +[`proxy_enqueue_shared_queue`] and/or [`proxy_dequeue_shared_queue`] +with `return_queue_id`. + +Returned `status` value is: +- `OK` on success. +- `NOT_FOUND` when the requested queue was not found. +- `INVALID_MEMORY_ACCESS` when `vm_id_data`, `vm_id_size`, `name_data`, + `name_size` and/or `return_queue_id` point to invalid memory address. + + +#### `proxy_enqueue_shared_queue` + +* params: + - `i32 (uint32_t) queue_id` + - `i32 (const uint8_t *) value_data` + - `i32 (size_t) value_size` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Adds item (`value_data`, `value_size`) to the end of the queue +`queue_id`. + +Returned `status` value is: +- `OK` on success. +- `NOT_FOUND` when the requested `queue_id` was not found. +- `INVALID_MEMORY_ACCESS` when `value_data` and/or `value_size` point + to invalid memory address. + + +#### `proxy_dequeue_shared_queue` + +* params: + - `i32 (uint32_t) queue_id` + - `i32 (uint8_t **) return_value_data` + - `i32 (size_t *) return_value_size` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Retrieves value (`return_value_data`, `return_value_size`) from +the front of the queue `queue_id`. + +Returned `status` value is: +- `OK` on success. +- `NOT_FOUND` when the requested `queue_id` was not found. +- `EMPTY` when there is nothing to dequeue from the requested queue. +- `INVALID_MEMORY_ACCESS` when `return_value_data` + and/or `return_value_size` point to invalid memory address. + + +### Callbacks exposed by the Wasm module + +#### `proxy_on_queue_ready` +* params: + - `i32 (uint32_t) plugin_context_id` + - `i32 (uint32_t) queue_id` +* returns: + - none + +Called when a new item is enqueued on the queue `queue_id`. + + +## Metrics + +### Functions exposed by the host + +#### `proxy_define_metric` + +* params: + - `i32 (`[`proxy_metric_type_t`]`) metric_type` + - `i32 (const char *) name_data` + - `i32 (size_t) name_size` + - `i32 (uint32_t *) return_metric_id` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Defines a new metric of type `metric_type` with a name (`name_data`, +`name_size`). + +Its value can be modified and/or retrieved using +[`proxy_record_metric`], [`proxy_increment_metric`] +and/or [`proxy_get_metric`] with `return_metric_id`. + +Returned `status` value is: +- `OK` on success. +- `BAD_ARGUMENT` for unknown `metric_type`. +- `INVALID_MEMORY_ACCESS` when `name_data`, `name_size` + and/or `return_metric_id` point to invalid memory address. + + +#### `proxy_record_metric` + +* params: + - `i32 (uint32_t) metric_id` + - `i64 (uint64_t) value` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Sets metric `metric_id` to the `value`. + +Returned `status` value is: +- `OK` on success. +- `NOT_FOUND` when the requested `metric_id` was not found. + + +#### `proxy_increment_metric` + +* params: + - `i32 (uint32_t) metric_id` + - `i64 (int64_t) offset` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Changes metric `metric_id` by the `offset`. + +Returned `status` value is: +- `OK` on success. +- `NOT_FOUND` when the requested `metric_id` was not found. +- `BAD_ARGUMENT` when requested `offset` cannot be applied to + `metric_id` (e.g. trying to decrement counter). + + +#### `proxy_get_metric` + +* params: + - `i32 (uint32_t) metric_id` + - `i32 (uint64_t *) return_value` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Retrieves `return_value` of the metric `metric_id`. + +Returned `status` value is: +- `OK` on success. +- `NOT_FOUND` when the requested `metric_id` was not found. +- `INVALID_MEMORY_ACCESS` when `return_value` points to invalid memory + address. + + +## Properties + +> **Warning** +> Properties are implementation-dependent and not stable. + +### Functions exposed by the host + +#### `proxy_get_property` + +* params: + - `i32 (const uint8_t *) path_data` + - `i32 (size_t) path_size` + - `i32 (uint8_t **) return_value_data` + - `i32 (size_t *) return_value_size` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Retrievies value (`return_value_data`, `return_value_size`) +of the property (`path_data`, `path_size`). + +Returned `status` value is: +- `OK` on success. +- `NOT_FOUND` when there was no property found at the requested `path`. +- `SERIALIZATION_FAILURE` TODO +- `INVALID_MEMORY_ACCESS` when `path_data`, `path_size`, + `return_value_data` and/or `return_value_size` point to invalid + memory address. + + +#### `proxy_set_property` + +* params: + - `i32 (const uint8_t *) path_data` + - `i32 (size_t) path_size` + - `i32 (const uint8_t *) value_data` + - `i32 (size_t) value_size` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Sets value of the property (`path_data`, `path_size`) to the provided +value (`value_data`, `value_size`). + +Returned `status` value is: +- `OK` on success. +- `NOT_FOUND` when there was no property found at the requested `path`. +- `INVALID_MEMORY_ACCESS` when `path_data`, `path_size`, `value_data` + and/or `value_size` point to invalid memory address. + + +## Foreign function interface (FFI) + +### Functions exposed by the host + +#### `proxy_call_foreign_function` + +* params: + - `i32 (const char *) name_data` + - `i32 (size_t) name_size` + - `i32 (const uint8_t *) arguments_data` + - `i32 (size_t) arguments_size` + - `i32 (uint8_t **) return_results_data` + - `i32 (size_t *) return_results_size` +* returns: + - `i32 (`[`proxy_status_t`]`) status` + +Calls registered foreign function (`name_data`, `name_size`) +with arguments (`arguments_data`, `arguments_size`). + +Return value(s) (`return_results_data`, `return_results_size`) +are optional. + +Returned `status` value is: +- `OK` on success. +- `NOT_FOUND` when the requested function was not found. +- `INVALID_MEMORY_ACCESS` when `name_data`, `name_size`, + `arguments_data`, `arguments_size`, `return_results_data` + and/or `return_results_size` point to invalid memory address. + + +### Callbacks exposed by the Wasm module + +#### `proxy_on_foreign_function` + +* params: + - `i32 (uint32_t) plugin_context_id` + - `i32 (uint32_t) function_id` + - `i32 (size_t) arguments_size` +* returns: + - none + +Called when a registered foreign callback `function_id` is called. + +Its arguments (of `arguments_size`) can be retrieved using +[`proxy_get_buffer_bytes`] with `buffer_id` set to +`FOREIGN_FUNCTION_ARGUMENTS`. + + +## Unimplemented WASI functions + +Various unimplemented WASI functions that are expected to be present +when the Wasm module is compiled for the `wasm32-wasi` target. + + +### Functions exposed by the host + +#### `wasi_snapshot_preview1.args_sizes_get` + +* params: + - `i32 (size_t *) return_argc` + - `i32 (size_t *) return_argv_buffer_size` +* returns: + - `i32 (`[`wasi_errno_t`]`) errno` + +Hosts must write `0` to both output arguments to prevent +[`wasi_snapshot_preview1.args_get`] from being called. + +Returned `errno` value is: +- `SUCCESS` on success. +- `FAULT` when `return_argc` and/or `return_argv_buffer_size` point to + invalid memory address. + + +#### `wasi_snapshot_preview1.args_get` + +* params: + - `i32 (uint8_t **) return_argv` + - `i32 (uint8_t *) return_argv_size` +* returns: + - `i32 (`[`wasi_errno_t`]`) errno` + +This function should not be called if zero sizes were returned +in [`wasi_snapshot_preview1.args_sizes_get`]. + +Returned `errno` value is: +- `SUCCESS` on success. + + +#### `wasi_snapshot_preview1.proc_exit` + +* params: + - `i32 (uint32_t) exit_code` +* returns: + - none + +This function is never called. + + +# Types + +#### `proxy_log_level_t` + +- `TRACE` = `0` +- `DEBUG` = `1` +- `INFO` = `2` +- `WARN` = `3` +- `ERROR` = `4` +- `CRITICAL` = `5` + + +#### `proxy_status_t` + +- `OK` = `0` +- `NOT_FOUND` = `1` +- `BAD_ARGUMENT` = `2` +- `SERIALIZATION_FAILURE` = `3` +- `PARSE_FAILURE` = `4` +- `INVALID_MEMORY_ACCESS` = `6` +- `EMPTY` = `7` +- `CAS_MISMATCH` = `8` +- `INTERNAL_FAILURE` = `10` +- `UNIMPLEMENTED` = `12` + + +#### `proxy_action_t` + +- `CONTINUE` = `0` +- `PAUSE` = `1` + + +#### `proxy_buffer_type_t` + +- `HTTP_REQUEST_BODY` = `0` +- `HTTP_RESPONSE_BODY` = `1` +- `DOWNSTREAM_DATA` = `2` +- `UPSTREAM_DATA` = `3` +- `HTTP_CALL_RESPONSE_BODY` = `4` +- `GRPC_CALL_MESSAGE` = `5` +- `VM_CONFIGURATION` = `6` +- `PLUGIN_CONFIGURATION` = `7` +- `FOREIGN_FUNCTION_ARGUMENTS` = `8` + + +#### `proxy_header_map_type_t` + +- `HTTP_REQUEST_HEADERS` = `0` +- `HTTP_REQUEST_TRAILERS` = `1` +- `HTTP_RESPONSE_HEADERS` = `2` +- `HTTP_RESPONSE_TRAILERS` = `3` +- `GRPC_CALL_INITIAL_METADATA` = `4` +- `GRPC_CALL_TRAILING_METADATA` = `5` +- `HTTP_CALL_RESPONSE_HEADERS` = `6` +- `HTTP_CALL_RESPONSE_TRAILERS` = `7` + + +#### `proxy_peer_type_t` + +- `UNKNOWN` = `0` +- `LOCAL` = `1` +- `REMOTE` =`2` + + +#### `proxy_stream_type_t` + +- `HTTP_REQUEST` = `0` +- `HTTP_RESPONSE` = `1` +- `DOWNSTREAM` = `2` +- `UPSTREAM` = `3` + + +#### `proxy_metric_type_t` + +- `COUNTER` = `0` +- `GAUGE` = `1` +- `HISTOGRAM` = `2` + + +#### `wasi_errno_t` + +- `SUCCESS` = `0` +- `BADF` = `8` +- `FAULT` = `21` +- `INVAL` = `28` +- `NOTSUP` = `58` + + +#### `wasi_fd_id_t` + +- `STDOUT` = `1` +- `STDERR` = `2` + + +#### `wasi_clock_id_t` + +- `REALTIME` = `0` +- `MONOTONIC` = `1` + + +# Serialization + +## HTTP fields and gRPC metadata + +TODO + + +[integration]: #Integration +[memory management]: #Memory-management +[serialized]: #Serialization + +[`proxy_abi_version_0_2_1`]: #proxy_abi_version_0_2_1 +[`_initialize`]: #_initialize +[`main`]: #main +[`_start`]: #_start +[`proxy_on_memory_allocate`]: #proxy_on_memory_allocate +[`malloc`]: #malloc +[`proxy_on_context_create`]: #proxy_on_context_create +[`proxy_on_done`]: #proxy_on_done +[`proxy_on_log`]: #proxy_on_log +[`proxy_on_delete`]: #proxy_on_delete +[`proxy_done`]: #proxy_done +[`proxy_set_effective_context`]: #proxy_set_effective_context +[`proxy_on_vm_start`]: #proxy_on_vm_start +[`proxy_on_configure`]: #proxy_on_configure +[`proxy_log`]: #proxy_log +[`proxy_get_log_level`]: #proxy_get_log_level +[`proxy_get_current_time_nanoseconds`]: #proxy_get_current_time_nanoseconds +[`proxy_set_tick_period_milliseconds`]: #proxy_set_tick_period_milliseconds +[`proxy_on_tick`]: #proxy_on_tick +[`proxy_set_buffer_bytes`]: #proxy_set_buffer_bytes +[`proxy_get_buffer_bytes`]: #proxy_get_buffer_bytes +[`proxy_get_buffer_status`]: #proxy_get_buffer_status +[`proxy_get_header_map_size`]: #proxy_get_header_map_size +[`proxy_get_header_map_pairs`]: #proxy_get_header_map_pairs +[`proxy_set_header_map_pairs`]: #proxy_set_header_map_pairs +[`proxy_get_header_map_value`]: #proxy_get_header_map_value +[`proxy_add_header_map_value`]: #proxy_add_header_map_value +[`proxy_replace_header_map_value`]: #proxy_replace_header_map_value +[`proxy_remove_header_map_value`]: #proxy_remove_header_map_value +[`proxy_continue_stream`]: #proxy_continue_stream +[`proxy_close_stream`]: #proxy_close_stream +[`proxy_on_new_connection`]: #proxy_on_new_connection +[`proxy_on_downstream_data`]: #proxy_on_downstream_data +[`proxy_on_downstream_connection_close`]: #proxy_on_downstream_connection_close +[`proxy_on_upstream_data`]: #proxy_on_upstream_data +[`proxy_on_upstream_connection_close`]: #proxy_on_upstream_connection_close +[`proxy_on_request_headers`]: #proxy_on_request_headers +[`proxy_on_request_body`]: #proxy_on_request_body +[`proxy_on_request_trailers`]: #proxy_on_request_trailers +[`proxy_on_response_headers`]: #proxy_on_response_headers +[`proxy_on_response_body`]: #proxy_on_response_body +[`proxy_on_response_trailers`]: #proxy_on_response_trailers +[`proxy_send_local_response`]: #proxy_send_local_response +[`proxy_http_call`]: #proxy_http_call +[`proxy_on_http_call_response`]: #proxy_on_http_call_response +[`proxy_grpc_call`]: #proxy_grpc_call +[`proxy_grpc_stream`]: #proxy_grpc_stream +[`proxy_grpc_send`]: #proxy_grpc_send +[`proxy_grpc_cancel`]: #proxy_grpc_cancel +[`proxy_grpc_close`]: #proxy_grpc_close +[`proxy_get_status`]: #proxy_get_status +[`proxy_on_grpc_receive_initial_metadata`]: #proxy_on_grpc_receive_initial_metadata +[`proxy_on_grpc_receive`]: #proxy_on_grpc_receive +[`proxy_on_grpc_receive_trailing_metadata`]: #proxy_on_grpc_receive_trailing_metadata +[`proxy_on_grpc_close`]: #proxy_on_grpc_close +[`proxy_set_shared_data`]: #proxy_set_shared_data +[`proxy_get_shared_data`]: #proxy_get_shared_data +[`proxy_register_shared_queue`]: #proxy_register_shared_queue +[`proxy_resolve_shared_queue`]: #proxy_resolve_shared_queue +[`proxy_enqueue_shared_queue`]: #proxy_enqueue_shared_queue +[`proxy_dequeue_shared_queue`]: #proxy_dequeue_shared_queue +[`proxy_on_queue_ready`]: #proxy_on_queue_ready +[`proxy_define_metric`]: #proxy_define_metric +[`proxy_record_metric`]: #proxy_record_metric +[`proxy_increment_metric`]: #proxy_increment_metric +[`proxy_get_metric`]: #proxy_get_metric +[`proxy_get_property`]: #proxy_get_property +[`proxy_set_property`]: #proxy_set_property +[`proxy_call_foreign_function`]: #proxy_call_foreign_function +[`proxy_on_foreign_function`]: #proxy_on_foreign_function + +[`wasi_snapshot_preview1.fd_write`]: #wasi_snapshot_preview1.fd_write +[`wasi_snapshot_preview1.clock_time_get`]: #wasi_snapshot_preview1.clock_time_get +[`wasi_snapshot_preview1.random_get`]: #wasi_snapshot_preview1.random_get +[`wasi_snapshot_preview1.environ_sizes_get`]: #wasi_snapshot_preview1.environ_sizes_get +[`wasi_snapshot_preview1.environ_get`]: #wasi_snapshot_preview1.environ_get +[`wasi_snapshot_preview1.args_sizes_get`]: #wasi_snapshot_preview1.args_sizes_get +[`wasi_snapshot_preview1.args_get`]: #wasi_snapshot_preview1.args_get +[`wasi_snapshot_preview1.proc_exit`]: #wasi_snapshot_preview1.proc_exit + +[`proxy_log_level_t`]: #proxy_log_level_t +[`proxy_status_t`]: #proxy_status_t +[`proxy_action_t`]: #proxy_action_t +[`proxy_buffer_type_t`]: #proxy_buffer_type_t +[`proxy_header_map_type_t`]: #proxy_header_map_type_t +[`proxy_peer_type_t`]: #proxy_peer_type_t +[`proxy_stream_type_t`]: #proxy_stream_type_t +[`proxy_metric_type_t`]: #proxy_metric_type_t + +[`wasi_errno_t`]: #wasi_errno_t +[`wasi_fd_id_t`]: #wasi_fd_id_t +[`wasi_clock_id_t`]: #wasi_clock_id_t From 839363d201fcf5be434525ee9812c567ca0eebcd Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Sat, 27 Jul 2024 07:54:56 -0400 Subject: [PATCH 02/28] review: add terminology section. Signed-off-by: Piotr Sikora --- abi-versions/v0.2.1/README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/abi-versions/v0.2.1/README.md b/abi-versions/v0.2.1/README.md index 307703b..3e0dd8c 100644 --- a/abi-versions/v0.2.1/README.md +++ b/abi-versions/v0.2.1/README.md @@ -6,6 +6,26 @@ Status: **FINAL** --- +# Terminology + +- *Plugin* - a WebAssembly module implementing Proxy-Wasm ABI. There are + 3 types of plugins: *HTTP*, *Stream* (TCP) and *Background task*. + +- *Host* - a proxy or another environment that executes Proxy-Wasm Plugin + inside the WebAssembly Virtual Machine (WasmVM). + +- *Hostcall* - a function call from Plugin to Host. + +- *Callback* - a function call from Host to Plugin (usually, as a result + of an external event). + +- *Plugin Context* (also known as *Root Context*) - a context in which + operations not related to any specific request or stream are executed. + +- *Stream Context* - a context in which operations from a specific HTTP + request/response pair or TCP stream are executed. + + # Callbacks and Functions ### Callbacks exposed by the Wasm module From 1ac04fae7122aa195ba43baf7eb38439b91afcc3 Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Sat, 27 Jul 2024 08:07:08 -0400 Subject: [PATCH 03/28] review: add missing serialized_ prefixes. Signed-off-by: Piotr Sikora --- abi-versions/v0.2.1/README.md | 38 ++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/abi-versions/v0.2.1/README.md b/abi-versions/v0.2.1/README.md index 3e0dd8c..4661d59 100644 --- a/abi-versions/v0.2.1/README.md +++ b/abi-versions/v0.2.1/README.md @@ -623,17 +623,17 @@ specific callbacks: * params: - `i32 (`[`proxy_header_map_type_t`]`) map_id` - - `i32 (size_t *) return_pairs_size` + - `i32 (size_t *) return_serialized_pairs_size` * returns: - `i32 (`[`proxy_status_t`]`) status` -Retrieves size (`return_pairs_size`) of all key-value pairs from -the header map `map_id`. +Retrieves size (`return_serialized_pairs_size`) of all key-value pairs +from the header map `map_id`. Returned `status` value is: - `OK` on success. - `BAD_ARGUMENT` for unknown `map_id`. -- `INVALID_MEMORY_ACCESS` when `return_pairs_size` points to +- `INVALID_MEMORY_ACCESS` when `return_serialized_pairs_size` points to invalid memory address. @@ -654,8 +654,8 @@ Returned header map (`return_serialized_pairs_data`, Returned `status` value is: - `OK` on success. - `BAD_ARGUMENT` for unknown `map_id`. -- `INVALID_MEMORY_ACCESS` when `return_pairs_data` and/or - `return_pairs_size` point to invalid memory address. +- `INVALID_MEMORY_ACCESS` when `return_serialized_pairs_data` and/or + `return_serialized_pairs_size` point to invalid memory address. #### `proxy_set_header_map_pairs` @@ -673,8 +673,8 @@ Sets all key-value pairs in the header map `map_id` to the provided Returned `status` value is: - `OK` on success. - `BAD_ARGUMENT` for unknown `map_id`. -- `INVALID_MEMORY_ACCESS` when `pairs_data` and/or - `pairs_size` point to invalid memory address. +- `INVALID_MEMORY_ACCESS` when `serialized_pairs_data` and/or + `serialized_pairs_size` point to invalid memory address. #### `proxy_get_header_map_value` @@ -1141,8 +1141,9 @@ downstream. Returned `status` value is: - `OK` on success. - `INVALID_MEMORY_ACCESS` when `status_code_details_data`, - `status_code_details_size`, `body_data`, `body_size`, `headers_data` - and/or `headers_size` point to invalid memory address. + `status_code_details_size`, `body_data`, `body_size`, + `serialized_headers_data` and/or `serialized_headers_size` + point to invalid memory address. ## HTTP calls @@ -1179,9 +1180,9 @@ Returned `status` value is: required `:authority`, `:method` and/or `:path` values. - `INTERNAL_FAILURE` when the host failed to send requested HTTP call. - `INVALID_MEMORY_ACCESS` when `upstream_data`, `upstream_size`, - `headers_data`, `headers_size` `body_data`, `body_size`, - `trailers_data`, `trailers_size` and/or `return_call_id` point to - invalid memory address. + `serialized_headers_data`, `serialized_headers_size` `body_data`, + `body_size`, `serialized_trailers_data`, `serialized_trailers_size` + and/or `return_call_id` point to invalid memory address. ### Callbacks exposed by the Wasm module @@ -1259,9 +1260,9 @@ Returned `status` value is: - `INTERNAL_FAILURE` when the host failed to send a gRPC call. - `INVALID_MEMORY_ACCESS` when `upstream_data`, `upstream_size`, `service_name_data`, `service_name_size` `method_name_data`, - `method_name_size`, `initial_metadata_data`, `initial_metadata_size`, - `message_data`, `message_size` and/or `return_call_id` point to - invalid memory address. + `method_name_size`, `serialized_initial_metadata_data`, + `serialized_initial_metadata_size`, `message_data`, `message_size` + and/or `return_call_id` point to invalid memory address. #### `proxy_grpc_stream` @@ -1302,8 +1303,9 @@ Returned `status` value is: - `INTERNAL_FAILURE` when the host failed to open gRPC stream. - `INVALID_MEMORY_ACCESS` when `upstream_data`, `upstream_size`, `service_name_data`, `service_name_size` `method_name_data`, - `method_name_size`, `initial_metadata_data`, `initial_metadata_size` - and/or `return_stream_id` point to invalid memory address. + `method_name_size`, `serialized_initial_metadata_data`, + `serialized_initial_metadata_size` and/or `return_stream_id` + point to invalid memory address. #### `proxy_grpc_send` From 26b7a994ce7a87f888cb5e09767434f4bb34802d Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Sat, 27 Jul 2024 08:09:34 -0400 Subject: [PATCH 04/28] review: rename proxy_header_map_type_t to proxy_map_type_t. Signed-off-by: Piotr Sikora --- abi-versions/v0.2.1/README.md | 36 +++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/abi-versions/v0.2.1/README.md b/abi-versions/v0.2.1/README.md index 4661d59..d1cca41 100644 --- a/abi-versions/v0.2.1/README.md +++ b/abi-versions/v0.2.1/README.md @@ -622,13 +622,13 @@ specific callbacks: #### `proxy_get_header_map_size` * params: - - `i32 (`[`proxy_header_map_type_t`]`) map_id` + - `i32 (`[`proxy_map_type_t`]`) map_id` - `i32 (size_t *) return_serialized_pairs_size` * returns: - `i32 (`[`proxy_status_t`]`) status` Retrieves size (`return_serialized_pairs_size`) of all key-value pairs -from the header map `map_id`. +from the map `map_id`. Returned `status` value is: - `OK` on success. @@ -640,15 +640,15 @@ Returned `status` value is: #### `proxy_get_header_map_pairs` * params: - - `i32 (`[`proxy_header_map_type_t`]`) map_id` + - `i32 (`[`proxy_map_type_t`]`) map_id` - `i32 (uint8_t **) return_serialized_pairs_data` - `i32 (size_t *) return_serialized_pairs_size` * returns: - `i32 (`[`proxy_status_t`]`) status` -Retrieves all key-value pairs from the header map `map_id`. +Retrieves all key-value pairs from the map `map_id`. -Returned header map (`return_serialized_pairs_data`, +Returned map (`return_serialized_pairs_data`, `return_serialized_pairs_size`) is [serialized]. Returned `status` value is: @@ -661,13 +661,13 @@ Returned `status` value is: #### `proxy_set_header_map_pairs` * params: - - `i32 (`[`proxy_header_map_type_t`]`) map_id` + - `i32 (`[`proxy_map_type_t`]`) map_id` - `i32 (const uint8_t *) serialized_pairs_data` - `i32 (size_t) serialized_pairs_size` * returns: - `i32 (`[`proxy_status_t`]`) status` -Sets all key-value pairs in the header map `map_id` to the provided +Sets all key-value pairs in the map `map_id` to the provided [serialized] map (`serialized_pairs_data`, `serialized_pairs_size`). Returned `status` value is: @@ -680,7 +680,7 @@ Returned `status` value is: #### `proxy_get_header_map_value` * params: - - `i32 (`[`proxy_header_map_type_t`]`) map_id` + - `i32 (`[`proxy_map_type_t`]`) map_id` - `i32 (const char *) key_data` - `i32 (size_t) key_size` - `i32 (uint8_t **) return_value_data` @@ -688,8 +688,8 @@ Returned `status` value is: * returns: - `i32 (`[`proxy_status_t`]`) status` -Retrieves value (`return_value_data`, `return_value_size`) of the header -key (`key_data`, `key_value`) from the header map `map_id`. +Retrieves value (`return_value_data`, `return_value_size`) of the key +(`key_data`, `key_value`) from the map `map_id`. Returned `status` value is: - `OK` on success. @@ -703,7 +703,7 @@ Returned `status` value is: #### `proxy_add_header_map_value` * params: - - `i32 (`[`proxy_header_map_type_t`]`) map_id` + - `i32 (`[`proxy_map_type_t`]`) map_id` - `i32 (const char *) key_data` - `i32 (size_t) key_size` - `i32 (const uint8_t *) value_data` @@ -712,7 +712,7 @@ Returned `status` value is: - `i32 (`[`proxy_status_t`]`) status` Adds key (`key_data`, `key_size`) with value (`value_data`, -`value_size`) to the header map `map_id`. +`value_size`) to the map `map_id`. Returned `status` value is: - `OK` on success. @@ -724,7 +724,7 @@ Returned `status` value is: #### `proxy_replace_header_map_value` * params: - - `i32 (`[`proxy_header_map_type_t`]`) map_id` + - `i32 (`[`proxy_map_type_t`]`) map_id` - `i32 (const char *) key_data` - `i32 (size_t) key_size` - `i32 (const uint8_t *) value_data` @@ -733,7 +733,7 @@ Returned `status` value is: - `i32 (`[`proxy_status_t`]`) status` Adds or replaces key's (`key_data`, `key_value`) value with the provided -value (`value_data`, `value_size`) in the header map `map_id`. +value (`value_data`, `value_size`) in the map `map_id`. Returned `status` value is: - `OK` on success. @@ -745,13 +745,13 @@ Returned `status` value is: #### `proxy_remove_header_map_value` * params: - - `i32 (`[`proxy_header_map_type_t`]`) map_id` + - `i32 (`[`proxy_map_type_t`]`) map_id` - `i32 (const char *) key_data` - `i32 (size_t) key_size` * returns: - `i32 (`[`proxy_status_t`]`) status` -Removes the key (`key_data`, `key_value`) from the header map `map_id`. +Removes the key (`key_data`, `key_value`) from the map `map_id`. Returned `status` value is: - `OK` on success (including the case when requested key didn't exist). @@ -1858,7 +1858,7 @@ This function is never called. - `FOREIGN_FUNCTION_ARGUMENTS` = `8` -#### `proxy_header_map_type_t` +#### `proxy_map_type_t` - `HTTP_REQUEST_HEADERS` = `0` - `HTTP_REQUEST_TRAILERS` = `1` @@ -2008,7 +2008,7 @@ TODO [`proxy_status_t`]: #proxy_status_t [`proxy_action_t`]: #proxy_action_t [`proxy_buffer_type_t`]: #proxy_buffer_type_t -[`proxy_header_map_type_t`]: #proxy_header_map_type_t +[`proxy_map_type_t`]: #proxy_map_type_t [`proxy_peer_type_t`]: #proxy_peer_type_t [`proxy_stream_type_t`]: #proxy_stream_type_t [`proxy_metric_type_t`]: #proxy_metric_type_t From b6448f45668331a95b850c8c21954e5f857d7c1a Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Sat, 27 Jul 2024 08:20:23 -0400 Subject: [PATCH 05/28] review: describe prepend/append/inject/replace operations. Signed-off-by: Piotr Sikora --- abi-versions/v0.2.1/README.md | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/abi-versions/v0.2.1/README.md b/abi-versions/v0.2.1/README.md index d1cca41..d289087 100644 --- a/abi-versions/v0.2.1/README.md +++ b/abi-versions/v0.2.1/README.md @@ -525,8 +525,8 @@ specific callbacks: * params: - `i32 (`[`proxy_buffer_type_t`]`) buffer_id` - - `i32 (uint32_t) offset` - - `i32 (uint32_t) size` + - `i32 (size_t) start` + - `i32 (size_t) size` - `i32 (const uint8_t *) value_data` - `i32 (size_t) value_size` * returns: @@ -534,7 +534,12 @@ specific callbacks: Sets content of the buffer `buffer_id` to the provided value (`value_data`, `value_size`) replacing `size` bytes starting -at `offset` in the existing buffer. +at `start` in the existing buffer. + +The combination of `start` and `size` parameters can be used to perform +prepend (`start=0`, `size=0`), append (`start` larger or equal than the +existing buffer size, may be set to the maximum `size_t` value), inject +and replace (`start` smaller than the existing buffer size) operations. Returned `status` value is: - `OK` on success. @@ -548,20 +553,20 @@ Returned `status` value is: * params: - `i32 (`[`proxy_buffer_type_t`]`) buffer_id` - - `i32 (uint32_t) offset` - - `i32 (uint32_t) max_size` + - `i32 (size_t) start` + - `i32 (size_t) max_size` - `i32 (uint8_t **) return_value_data` - `i32 (size_t *) return_value_size` * returns: - `i32 (`[`proxy_status_t`]`) status` -Retrieves up to` max_size` bytes starting at `offset` from the buffer +Retrieves up to `max_size` bytes starting at `start` from the buffer `buffer_id`. Returned `status` value is: - `OK` on success. - `BAD_ARGUMENT` for unknown `buffer_id`, or in case of buffer overflow - due to invalid `offset` and/or `max_size` values. + due to invalid `start` and/or `max_size` values. - `NOT_FOUND` when requested `buffer_id` isn't available. - `INVALID_MEMORY_ACCESS` when `returned_value_data` and/or `returned_value_size` point to invalid memory address. From 80be4d7aa75b9e327e9e39ebb5d542898f429430 Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Sat, 27 Jul 2024 08:20:53 -0400 Subject: [PATCH 06/28] review: rename offset to delta in metrics. Signed-off-by: Piotr Sikora --- abi-versions/v0.2.1/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/abi-versions/v0.2.1/README.md b/abi-versions/v0.2.1/README.md index d289087..eb5b3d7 100644 --- a/abi-versions/v0.2.1/README.md +++ b/abi-versions/v0.2.1/README.md @@ -1641,16 +1641,16 @@ Returned `status` value is: * params: - `i32 (uint32_t) metric_id` - - `i64 (int64_t) offset` + - `i64 (int64_t) delta` * returns: - `i32 (`[`proxy_status_t`]`) status` -Changes metric `metric_id` by the `offset`. +Changes metric `metric_id` by the `delta`. Returned `status` value is: - `OK` on success. - `NOT_FOUND` when the requested `metric_id` was not found. -- `BAD_ARGUMENT` when requested `offset` cannot be applied to +- `BAD_ARGUMENT` when requested `delta` cannot be applied to `metric_id` (e.g. trying to decrement counter). From ed47949ad8f71a695c5a896d1b25446ac845041e Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Sat, 27 Jul 2024 08:21:13 -0400 Subject: [PATCH 07/28] review: drop UDP and QUIC streams from the documentation. Signed-off-by: Piotr Sikora --- abi-versions/v0.2.1/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abi-versions/v0.2.1/README.md b/abi-versions/v0.2.1/README.md index eb5b3d7..712c943 100644 --- a/abi-versions/v0.2.1/README.md +++ b/abi-versions/v0.2.1/README.md @@ -820,7 +820,7 @@ Returned `status` value is: point to invalid memory address. -## TCP/UDP/QUIC streams +## TCP streams > **Note** > `downstream` refers to the connection between client and proxy, From 8eda24fc409b751155d50754d1a02031b67b12d5 Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Sat, 27 Jul 2024 08:34:01 -0400 Subject: [PATCH 08/28] review: document disabling the timer. Signed-off-by: Piotr Sikora --- abi-versions/v0.2.1/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/abi-versions/v0.2.1/README.md b/abi-versions/v0.2.1/README.md index 712c943..1cae832 100644 --- a/abi-versions/v0.2.1/README.md +++ b/abi-versions/v0.2.1/README.md @@ -411,6 +411,8 @@ Returned `errno` value is: Sets timer period (`tick_period`). When set, the host will call [`proxy_on_tick`] every `tick_period` milliseconds. +Setting `tick_period` to `0` disables the timer. + Returned `status` value is: - `OK` on success. From ceda8b1e37b54a711468ff8335c81ef5902c65aa Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Sat, 27 Jul 2024 09:39:40 -0400 Subject: [PATCH 09/28] review: document serialization. Signed-off-by: Piotr Sikora --- abi-versions/v0.2.1/README.md | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/abi-versions/v0.2.1/README.md b/abi-versions/v0.2.1/README.md index 1cae832..aba9116 100644 --- a/abi-versions/v0.2.1/README.md +++ b/abi-versions/v0.2.1/README.md @@ -1922,9 +1922,25 @@ This function is never called. # Serialization -## HTTP fields and gRPC metadata +> **Note** +> The encoding of integers is little-endian. + + +#### Maps with HTTP fields and/or gRPC metadata + +Non-empty maps are serialized as: +- 32-bit integer containing the number of keys in the map, +- a series of pairs of 32-bit integers containing length of key and value, +- a series of pairs of bytes containing key and value, separated by `NULL` + (`0x00`) character. + +e.g. the map `{{"a": "1"}, {"b": "22"}}` would be serialized as: +- `0x02`, +- `0x01`, `0x01`, `0x01`, `0x02`, +- `0x61`, `0x00`, `0x49`, `0x00`, `0x62`, `0x00`, `0x50`, `0x50`, `0x00`. -TODO +An empty map may be represented either as an empty value (`size=0`), or as +a single `0x00` byte (`size=1`). [integration]: #Integration From a426901323995175cd78be1b744a9e042d093959 Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Sat, 27 Jul 2024 09:40:05 -0400 Subject: [PATCH 10/28] review: add links to types. Signed-off-by: Piotr Sikora --- abi-versions/v0.2.1/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/abi-versions/v0.2.1/README.md b/abi-versions/v0.2.1/README.md index aba9116..7b5192b 100644 --- a/abi-versions/v0.2.1/README.md +++ b/abi-versions/v0.2.1/README.md @@ -497,8 +497,8 @@ Returned `errno` value is: ## Buffers -Access to buffers using functions in this section is restricted to -specific callbacks: +Access to buffers (listed in [`proxy_buffer_type_t`]) using functions +in this section is restricted to specific callbacks: - `HTTP_REQUEST_BODY` can be read and modified in [`proxy_on_request_body`] (or for as long as request processing @@ -595,8 +595,8 @@ Returned `status` value is: ## HTTP fields -Access to HTTP fields using functions in this section is restricted to -specific callbacks: +Access to HTTP fields (listed in [`proxy_map_type_t`]) using +functions in this section is restricted to specific callbacks: - `HTTP_REQUEST_HEADERS` can be read in [`proxy_on_log`], and read and modified from [`proxy_on_request_headers`] From 087b962ccac47e2f40521bc3fa3c160544caecfb Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Sat, 27 Jul 2024 09:41:21 -0400 Subject: [PATCH 11/28] review: style. Signed-off-by: Piotr Sikora --- abi-versions/v0.2.1/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/abi-versions/v0.2.1/README.md b/abi-versions/v0.2.1/README.md index 7b5192b..e9e5600 100644 --- a/abi-versions/v0.2.1/README.md +++ b/abi-versions/v0.2.1/README.md @@ -938,6 +938,7 @@ Called when upstream connection is closed. > The same unique `stream_context_id` is shared by > HTTP request and response. + #### `proxy_on_request_headers` * params: @@ -1678,6 +1679,7 @@ Returned `status` value is: > **Warning** > Properties are implementation-dependent and not stable. + ### Functions exposed by the host #### `proxy_get_property` From d9eabb180dd0a66d0f5bb58d6878b4b7333c310d Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Sat, 27 Jul 2024 09:41:41 -0400 Subject: [PATCH 12/28] review: add note about corrections. Signed-off-by: Piotr Sikora --- abi-versions/v0.2.1/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abi-versions/v0.2.1/README.md b/abi-versions/v0.2.1/README.md index e9e5600..dd4ae54 100644 --- a/abi-versions/v0.2.1/README.md +++ b/abi-versions/v0.2.1/README.md @@ -2,7 +2,7 @@ --- -Status: **FINAL** +Status: **FINAL** (corrections and/or clarifications are welcomed) --- From 794a9f092a42a5404e54f61ff8438a3a47e643f9 Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Sat, 27 Jul 2024 09:52:04 -0400 Subject: [PATCH 13/28] review: describe SERIALIZATION_FAILURE. Signed-off-by: Piotr Sikora --- abi-versions/v0.2.1/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abi-versions/v0.2.1/README.md b/abi-versions/v0.2.1/README.md index dd4ae54..42a65fe 100644 --- a/abi-versions/v0.2.1/README.md +++ b/abi-versions/v0.2.1/README.md @@ -1698,7 +1698,7 @@ of the property (`path_data`, `path_size`). Returned `status` value is: - `OK` on success. - `NOT_FOUND` when there was no property found at the requested `path`. -- `SERIALIZATION_FAILURE` TODO +- `SERIALIZATION_FAILURE` when host failed to serialize property. - `INVALID_MEMORY_ACCESS` when `path_data`, `path_size`, `return_value_data` and/or `return_value_size` point to invalid memory address. From cda0ef033df050c622a62844b167ca320d80ed6d Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Sat, 27 Jul 2024 10:35:51 -0400 Subject: [PATCH 14/28] review: rename ignored to unused. Signed-off-by: Piotr Sikora --- abi-versions/v0.2.1/README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/abi-versions/v0.2.1/README.md b/abi-versions/v0.2.1/README.md index 42a65fe..35816e0 100644 --- a/abi-versions/v0.2.1/README.md +++ b/abi-versions/v0.2.1/README.md @@ -78,10 +78,10 @@ Called when the Wasm module is first loaded. #### `main` * params: - - `i32 (uint32_t) ignored` - - `i32 (uint32_t) ignored` + - `i32 (uint32_t) unused` + - `i32 (uint32_t) unused` * returns: - - `i32 (uint32_t) ignored` + - `i32 (uint32_t) unused` > **Warning** > This is called only if [`_initialize`] is also exported. @@ -250,7 +250,7 @@ Returned `status` value is: #### `proxy_on_vm_start` * params: - - `i32 (uint32_t) plugin_context_id` + - `i32 (uint32_t) unused` - `i32 (size_t) vm_configuration_size` * returns: - `i32 (bool) status` @@ -379,7 +379,7 @@ Returned `status` value is: * params: - `i32 (`[`wasi_clock_id_t`]`) clock_id` - - `i64 (uint64_t) ignored` + - `i64 (uint64_t) unused` - `i32 (uint64_t *) return_time` * returns: - `i32 (`[`wasi_errno_t`]`) errno` @@ -579,7 +579,7 @@ Returned `status` value is: * params: - `i32 (`[`proxy_buffer_type_t`]`) buffer_id` - `i32 (size_t *) return_buffer_size` - - `i32 (uint32_t *) return_ignored` + - `i32 (uint32_t *) return_unused` * returns: - `i32 (`[`proxy_status_t`]`) status` @@ -590,7 +590,7 @@ Returned `status` value is: - `BAD_ARGUMENT` for unknown `buffer_id`. - `NOT_FOUND` when requested `buffer_id` isn't available. - `INVALID_MEMORY_ACCESS` when `return_buffer_size` and/or - `return_ignored` point to invalid memory address. + `return_unused` point to invalid memory address. ## HTTP fields From 4dd2350b42d55d96a33fac4f3529538f57e6592e Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Sat, 27 Jul 2024 10:37:50 -0400 Subject: [PATCH 15/28] review: style. Signed-off-by: Piotr Sikora --- abi-versions/v0.2.1/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/abi-versions/v0.2.1/README.md b/abi-versions/v0.2.1/README.md index 35816e0..b858947 100644 --- a/abi-versions/v0.2.1/README.md +++ b/abi-versions/v0.2.1/README.md @@ -767,7 +767,7 @@ Returned `status` value is: invalid memory address. -## Common stream operations +## Common HTTP and TCP stream operations ### Functions exposed by the host @@ -930,7 +930,7 @@ Plugin must return one of the following values: Called when upstream connection is closed. -## HTTP +## HTTP streams ### Callbacks exposed by the Wasm module From 0ff5f6d1052ee4f245a68e76b8f04f88b53dc3e2 Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Sat, 27 Jul 2024 10:41:13 -0400 Subject: [PATCH 16/28] review: elaborate on on_start failures. Signed-off-by: Piotr Sikora --- abi-versions/v0.2.1/README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/abi-versions/v0.2.1/README.md b/abi-versions/v0.2.1/README.md index b858947..c68d48d 100644 --- a/abi-versions/v0.2.1/README.md +++ b/abi-versions/v0.2.1/README.md @@ -262,7 +262,8 @@ Its configuration (of `vm_configuration_size`) can be retrieved using Plugin must return one of the following values: - `true` to indicate that the configuration was processed successfully. -- `false` to indicate that the configuration processing failed. +- `false` to indicate that the configuration processing failed, and that + this instance of WasmVM shouldn't be used. #### `proxy_on_configure` @@ -281,7 +282,8 @@ using [`proxy_get_buffer_bytes`] with `buffer_id` set to Plugin must return one of the following values: - `true` to indicate that the configuration was processed successfully. -- `false` to indicate that the configuration processing failed. +- `false` to indicate that the configuration processing failed, and that + this instance of plugin shouldn't be used. ## Logging From 2ed0a44bd42ba0f845d022bc3ef316e106cb68f2 Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Tue, 30 Jul 2024 19:39:36 -0400 Subject: [PATCH 17/28] review: move Serialization before Types. Signed-off-by: Piotr Sikora --- abi-versions/v0.2.1/README.md | 46 +++++++++++++++++------------------ 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/abi-versions/v0.2.1/README.md b/abi-versions/v0.2.1/README.md index c68d48d..c5765cc 100644 --- a/abi-versions/v0.2.1/README.md +++ b/abi-versions/v0.2.1/README.md @@ -1824,6 +1824,29 @@ Returned `errno` value is: This function is never called. +# Serialization + +> **Note** +> The encoding of integers is little-endian. + + +#### Maps with HTTP fields and/or gRPC metadata + +Non-empty maps are serialized as: +- 32-bit integer containing the number of keys in the map, +- a series of pairs of 32-bit integers containing length of key and value, +- a series of pairs of bytes containing key and value, separated by `NULL` + (`0x00`) character. + +e.g. the map `{{"a": "1"}, {"b": "22"}}` would be serialized as: +- `0x02`, +- `0x01`, `0x01`, `0x01`, `0x02`, +- `0x61`, `0x00`, `0x49`, `0x00`, `0x62`, `0x00`, `0x50`, `0x50`, `0x00`. + +An empty map may be represented either as an empty value (`size=0`), or as +a single `0x00` byte (`size=1`). + + # Types #### `proxy_log_level_t` @@ -1924,29 +1947,6 @@ This function is never called. - `MONOTONIC` = `1` -# Serialization - -> **Note** -> The encoding of integers is little-endian. - - -#### Maps with HTTP fields and/or gRPC metadata - -Non-empty maps are serialized as: -- 32-bit integer containing the number of keys in the map, -- a series of pairs of 32-bit integers containing length of key and value, -- a series of pairs of bytes containing key and value, separated by `NULL` - (`0x00`) character. - -e.g. the map `{{"a": "1"}, {"b": "22"}}` would be serialized as: -- `0x02`, -- `0x01`, `0x01`, `0x01`, `0x02`, -- `0x61`, `0x00`, `0x49`, `0x00`, `0x62`, `0x00`, `0x50`, `0x50`, `0x00`. - -An empty map may be represented either as an empty value (`size=0`), or as -a single `0x00` byte (`size=1`). - - [integration]: #Integration [memory management]: #Memory-management [serialized]: #Serialization From 2be90d2b45761842dfc4294d29de9ca70079832c Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Tue, 30 Jul 2024 19:50:12 -0400 Subject: [PATCH 18/28] review: add Security Considerations. Signed-off-by: Piotr Sikora --- abi-versions/v0.2.1/README.md | 37 +++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/abi-versions/v0.2.1/README.md b/abi-versions/v0.2.1/README.md index c5765cc..df8d854 100644 --- a/abi-versions/v0.2.1/README.md +++ b/abi-versions/v0.2.1/README.md @@ -1847,6 +1847,43 @@ An empty map may be represented either as an empty value (`size=0`), or as a single `0x00` byte (`size=1`). +# Security Considerations + +## External resources + +Hosts should maintain a list of external resources (e.g. upstream hosts) +that each plugin instance can communicate with. + + +## Memory and CPU limits + +Hosts should enforce limits on memory usage and maximum CPU time that +plugins can consume during each invocation. + + +## Plugin crashes + +In case of a crashing WasmVM (e.g. because of a bug in Proxy-Wasm Plugin), +the host should log the information about the crash, including stacktrace, +and create a new instance of a WasmVM and the Proxy-Wasm Plugin. + +The number of crashes should be tracked and rate-limited to prevent entering +the crash-loop, where new instances keeps crashing and the creation of a new +WasmVM is consuming too much resources leading to a denial of service (DoS). + +Upon reaching the limit, the host should reject new connections and/or requests +that rely on the broken plugin, returning errors to clients, unless the plugin +is optional, in which case its execution may be skipped. + + +## Effective context changes + +Plugins can change the effective context to a different connection/request. + +Hosts should be aware of this, and might limit the ability to perform context +changes to unrelated connections/requests. + + # Types #### `proxy_log_level_t` From ffbc52ed5622e9a67908cfe3a62f225aad3b328b Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Tue, 30 Jul 2024 20:39:34 -0400 Subject: [PATCH 19/28] review: style/typos. Signed-off-by: Piotr Sikora --- abi-versions/v0.2.1/README.md | 68 +++++++++++++++++------------------ 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/abi-versions/v0.2.1/README.md b/abi-versions/v0.2.1/README.md index df8d854..e364872 100644 --- a/abi-versions/v0.2.1/README.md +++ b/abi-versions/v0.2.1/README.md @@ -450,7 +450,7 @@ Generates `buffer_size` bytes of randomness. Returned `errno` value is: - `SUCCESS` on success. -- `INVAL` when requested `buffer_size` is too large. +- `INVAL` when the requested `buffer_size` is too large. - `FAULT` when `buffer` and/or `buffer_size` point to invalid memory address. @@ -548,7 +548,7 @@ and replace (`start` smaller than the existing buffer size) operations. Returned `status` value is: - `OK` on success. - `BAD_ARGUMENT` for unknown `buffer_id`. -- `NOT_FOUND` when requested `buffer_id` isn't available. +- `NOT_FOUND` when the requested `buffer_id` isn't available. - `INVALID_MEMORY_ACCESS` when `value_data` and/or `value_size` point to invalid memory address. @@ -571,7 +571,7 @@ Returned `status` value is: - `OK` on success. - `BAD_ARGUMENT` for unknown `buffer_id`, or in case of buffer overflow due to invalid `start` and/or `max_size` values. -- `NOT_FOUND` when requested `buffer_id` isn't available. +- `NOT_FOUND` when the requested `buffer_id` isn't available. - `INVALID_MEMORY_ACCESS` when `returned_value_data` and/or `returned_value_size` point to invalid memory address. @@ -590,7 +590,7 @@ Retrieves size (`return_buffer_size`) of the buffer `buffer_id`. Returned `status` value is: - `OK` on success. - `BAD_ARGUMENT` for unknown `buffer_id`. -- `NOT_FOUND` when requested `buffer_id` isn't available. +- `NOT_FOUND` when the requested `buffer_id` isn't available. - `INVALID_MEMORY_ACCESS` when `return_buffer_size` and/or `return_unused` point to invalid memory address. @@ -763,7 +763,7 @@ Returned `status` value is: Removes the key (`key_data`, `key_value`) from the map `map_id`. Returned `status` value is: -- `OK` on success (including the case when requested key didn't exist). +- `OK` on success (including the case when the requested key didn't exist). - `BAD_ARGUMENT` for unknown `map_id`. - `INVALID_MEMORY_ACCESS` when `key_data` and/or `key_size` point to invalid memory address. @@ -785,7 +785,7 @@ Resumes processing of paused `stream_type`. Returned `status` value is: - `OK` on success. - `BAD_ARGUMENT` for unknown `stream_type`. -- `UNIMPLEMENTED` when continuation of requested `stream_type` +- `UNIMPLEMENTED` when continuation of the requested `stream_type` is not supported. @@ -864,9 +864,9 @@ Plugin must return one of the following values: Called for each data chunk received from downstream, even when the processing is paused. -`data_size` represents total available size of the data that can be -retrieved, and its value will increment if the processing is paused -and data is buffered by the host and not forwarded upstream. +`data_size` represents the total available size of the data that can be +retrieved, and its value will increment if the processing is paused and +data is buffered by the host and not forwarded upstream. Data (of `data_size`) can be retrieved and/or modified using [`proxy_get_buffer_bytes`] and/or [`proxy_set_buffer_bytes`] @@ -904,9 +904,9 @@ Called when downstream connection is closed. Called for each data chunk received from upstream, even when the processing is paused. -`data_size` represents total available size of the data that can be -retrieved, and its value will increment if the processing is paused -and data is buffered by the host and not forwarded downstream. +`data_size` represents the total available size of the data that can be +retrieved, and its value will increment if the processing is paused and +data is buffered by the host and not forwarded downstream. Data (of `data_size`) can be retrieved and/or modified using [`proxy_get_buffer_bytes`] and/or [`proxy_set_buffer_bytes`] @@ -961,12 +961,12 @@ Individual HTTP request headers can be retrieved and/or modified using [`proxy_add_header_map_value`] and/or [`proxy_remove_header_map_value`] with `map_id` set to `HTTP_REQUEST_HEADERS`. -Paused request can be resumed using [`proxy_continue_stream`] +Paused HTTP requests can be resumed using [`proxy_continue_stream`] or closed using [`proxy_close_stream`] with `stream_type` set to `HTTP_REQUEST`. -Additionally, instead of forwarding request upstream, a HTTP response -can be sent using [`proxy_send_local_response`]. +Additionally, instead of forwarding the HTTP request to upstream, +a HTTP response can be sent using [`proxy_send_local_response`]. Plugin must return one of the following values: - `CONTINUE` to forward `HTTP_REQUEST_HEADERS` fields downstream. @@ -989,15 +989,15 @@ Request body chunk (of `body_size`) can be retrieved and/or modified using [`proxy_get_buffer_bytes`] and/or [`proxy_set_buffer_bytes`] with `buffer_id` set to `HTTP_REQUEST_BODY`. -`body_size` represents total available size of the body that can be -retrieved, and its value will increment if the processing is paused -and the body is buffered by the host and not forwarded upstream. +`body_size` represents the total available size of the body that can be +retrieved, and its value will increment if the processing is paused and +the body is buffered by the host and not forwarded upstream. -Paused HTTP request can be resumed using [`proxy_continue_stream`] +Paused HTTP requests can be resumed using [`proxy_continue_stream`] or closed using [`proxy_close_stream`] with `stream_type` set to `HTTP_REQUEST`. -Additionally, as long as HTTP response headers were not send downstream, +Additionally, as long as HTTP response headers were not sent downstream, a HTTP response can be sent using [`proxy_send_local_response`]. Plugin must return one of the following values: @@ -1024,11 +1024,11 @@ Individual HTTP request trailers can be retrieved and/or modified using [`proxy_add_header_map_value`] and/or [`proxy_remove_header_map_value`] with `map_id` set to `HTTP_REQUEST_TRAILERS`. -Paused request can be resumed using [`proxy_continue_stream`] +Paused HTTP requests can be resumed using [`proxy_continue_stream`] or closed using [`proxy_close_stream`] with `stream_type` set to `HTTP_REQUEST`. -Additionally, as long as HTTP response headers were not send downstream, +Additionally, as long as HTTP response headers were not sent downstream, a HTTP response can be sent using [`proxy_send_local_response`]. Plugin must return one of the following values: @@ -1056,11 +1056,11 @@ Individual headers can be retrieved and/or modified using [`proxy_add_header_map_value`] and/or [`proxy_remove_header_map_value`] with `map_id` set to `HTTP_RESPONSE_HEADERS`. -Paused request can be resumed using [`proxy_continue_stream`] +Paused HTTP requests can be resumed using [`proxy_continue_stream`] or closed using [`proxy_close_stream`] with `stream_type` set to `HTTP_RESPONSE`. -Additionally, instead of forwarding the response from upstream, +Additionally, instead of forwarding the HTTP response from upstream, a new HTTP response can be sent using [`proxy_send_local_response`]. Plugin must return one of the following values: @@ -1084,11 +1084,11 @@ Response body chunk (of `body_size`) can be retrieved and/or modified using [`proxy_get_buffer_bytes`] and/or [`proxy_set_buffer_bytes`] with `buffer_id` set to `HTTP_RESPONSE_BODY`. -`body_size` represents total available size of the body that can be -retrieved, and its value will increment if the processing is paused -and the body is buffered by the host and not forwarded downstream. +`body_size` represents the total available size of the body that can be +retrieved, and its value will increment if the processing is paused and +the body is buffered by the host and not forwarded downstream. -Paused HTTP response can be resumed using [`proxy_continue_stream`] +Paused HTTP responses can be resumed using [`proxy_continue_stream`] or closed using [`proxy_close_stream`] with `stream_type` set to `HTTP_RESPONSE`. @@ -1116,7 +1116,7 @@ Individual trailers can be retrieved and/or modified using [`proxy_add_header_map_value`] and/or [`proxy_remove_header_map_value`] with `map_id` set to `HTTP_RESPONSE_TRAILERS`. -Paused request can be resumed using [`proxy_continue_stream`] +Paused HTTP requests can be resumed using [`proxy_continue_stream`] or closed using [`proxy_close_stream`] with `stream_type` set to `HTTP_REQUEST`. @@ -1188,7 +1188,7 @@ Returned `status` value is: - `OK` on success. - `BAD_ARGUMENT` for unknown `upstream`, or when `headers` are missing required `:authority`, `:method` and/or `:path` values. -- `INTERNAL_FAILURE` when the host failed to send requested HTTP call. +- `INTERNAL_FAILURE` when the host failed to send the requested HTTP call. - `INVALID_MEMORY_ACCESS` when `upstream_data`, `upstream_size`, `serialized_headers_data`, `serialized_headers_size` `body_data`, `body_size`, `serialized_trailers_data`, `serialized_trailers_size` @@ -1655,7 +1655,7 @@ Changes metric `metric_id` by the `delta`. Returned `status` value is: - `OK` on success. - `NOT_FOUND` when the requested `metric_id` was not found. -- `BAD_ARGUMENT` when requested `delta` cannot be applied to +- `BAD_ARGUMENT` when the requested `delta` cannot be applied to `metric_id` (e.g. trying to decrement counter). @@ -1694,7 +1694,7 @@ Returned `status` value is: * returns: - `i32 (`[`proxy_status_t`]`) status` -Retrievies value (`return_value_data`, `return_value_size`) +Retrieves value (`return_value_data`, `return_value_size`) of the property (`path_data`, `path_size`). Returned `status` value is: @@ -1868,8 +1868,8 @@ the host should log the information about the crash, including stacktrace, and create a new instance of a WasmVM and the Proxy-Wasm Plugin. The number of crashes should be tracked and rate-limited to prevent entering -the crash-loop, where new instances keeps crashing and the creation of a new -WasmVM is consuming too much resources leading to a denial of service (DoS). +the crash-loop, when new instances keep crashing and creation of new WasmVMs +is consuming too much resources leading to a denial of service (DoS). Upon reaching the limit, the host should reject new connections and/or requests that rely on the broken plugin, returning errors to clients, unless the plugin From 44a037732c03cb5bbddf2c838c87742571861fbe Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Tue, 30 Jul 2024 20:41:50 -0400 Subject: [PATCH 20/28] review: fix typo missed in the previous call. Signed-off-by: Piotr Sikora --- abi-versions/v0.2.1/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/abi-versions/v0.2.1/README.md b/abi-versions/v0.2.1/README.md index e364872..7b8b7cb 100644 --- a/abi-versions/v0.2.1/README.md +++ b/abi-versions/v0.2.1/README.md @@ -1145,8 +1145,7 @@ Sends HTTP response with body (`body_data`, `body_size`) and [serialized] headers (`serialized_headers_data`, `serialized_headers_size`). -This can be used as long as HTTP response headers were not send -downstream. +This can be used as long as HTTP response headers were not sent downstream. Returned `status` value is: - `OK` on success. From 56e25fc16d794f7e011148964d56a6ebbfb3f79d Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Thu, 1 Aug 2024 11:29:17 -0400 Subject: [PATCH 21/28] review: document well-known properties. Signed-off-by: Piotr Sikora --- abi-versions/v0.2.1/README.md | 87 ++++++++++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/abi-versions/v0.2.1/README.md b/abi-versions/v0.2.1/README.md index 7b8b7cb..6e7ed5c 100644 --- a/abi-versions/v0.2.1/README.md +++ b/abi-versions/v0.2.1/README.md @@ -1678,7 +1678,8 @@ Returned `status` value is: ## Properties > **Warning** -> Properties are implementation-dependent and not stable. +> Properties are implementation-dependent and not stable across +> different versions of the same host. ### Functions exposed by the host @@ -1725,6 +1726,90 @@ Returned `status` value is: and/or `value_size` point to invalid memory address. +### Well-known properties + +> **Warning** +> Properties are implementation-dependent and not stable across +> different versions of the same host. +> When targeting a specific host implementation (discouraged), +> please refer to its official documentation for a complete list +> of supported properties. + + +#### Proxy-Wasm properties + +* `plugin_name` (string) - plugin name +* `plugin_root_id` (string) - plugin root ID +* `plugin_vm_id` (string) - plugin VM ID + + +#### Downstream connection properties + +* `connection.id` (uint) - connection ID +* `source.address` (string) - remote address +* `source.port` (int) - remote port +* `destination.address` (string) - local address +* `destination.port` (int) - local port +* `connection.tls_version` (string) - TLS version +* `connection.requested_server_name` (string) - TLS SNI +* `connection.mtls` (bool) - true if the TLS client certificate was validated +* `connection.subject_local_certificate` (string) - subject of + the local certificate +* `connection.subject_peer_certificate` (string) - subject of + the peer certificate +* `connection.dns_san_local_certificate` (string) - first DNS entry in + the local certificate +* `connection.dns_san_peer_certificate` (string) - first DNS entry in + the the peer certificate +* `connection.uri_san_local_certificate` (string) - first URI entry in + the local certificate +* `connection.uri_san_peer_certificate` (string) - first URI entry in + the peer certificate +* `connection.sha256_peer_certificate_digest` (string) - SHA256 digest of + the peer certificate + + +#### Upstream connection properties + +* `upstream.address` (string) - remote address +* `upstream.port` (int) - remote port +* `upstream.local_address` (string) - local address +* `upstream.local_port` (int) - local port +* `upstream.tls_version` (string) - TLS version +* `upstream.subject_local_certificate` (string) - subject of + the local certificate +* `upstream.subject_peer_certificate` (string) - subject of + the peer certificate +* `upstream.dns_san_local_certificate` (string) - first DNS entry in + the local certificate +* `upstream.dns_san_peer_certificate` (string) - first DNS entry in + the peer certificate +* `upstream.uri_san_local_certificate` (string) - first URI entry in + the local certificate +* `upstream.uri_san_peer_certificate` (string) - first URI entry in + the peer certificate +* `upstream.sha256_peer_certificate_digest` (string) - SHA256 digest of + the peer certificate + + +#### HTTP request properties + +* `request.protocol` (string) - HTTP version + (`HTTP/1.0`, `HTTP/1.1`, `HTTP/2`, `HTTP/3`) +* `request.time` (timestamp) - time of the first byte received +* `request.duration` (duration) - total duration of the HTTP request +* `request.size` (int) - size of the HTTP request body +* `request.total_size` (int) - total size of the HTTP request + (including HTTP headers and trailers) + + +#### HTTP response properties + +* `response.size` (int) - size of the HTTP response body +* `response.total_size` (int) - total size of the HTTP response + (including HTTP headers and trailers) + + ## Foreign function interface (FFI) ### Functions exposed by the host From 8e26f8c2fcc4f8d5fa0482d56daea5076db9733e Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Fri, 2 Aug 2024 17:46:51 -0400 Subject: [PATCH 22/28] review: add note about host restrictions/capabilities. Signed-off-by: Piotr Sikora --- abi-versions/v0.2.1/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/abi-versions/v0.2.1/README.md b/abi-versions/v0.2.1/README.md index 6e7ed5c..fdfbd7c 100644 --- a/abi-versions/v0.2.1/README.md +++ b/abi-versions/v0.2.1/README.md @@ -31,7 +31,8 @@ Status: **FINAL** (corrections and/or clarifications are welcomed) ### Callbacks exposed by the Wasm module All callbacks (entry points named `proxy_on_`) are optional, -and are going to be called only if exposed by the Wasm module. +and are going to be called only if exposed by the Wasm module, and +not restricted by the host due to policy and/or other reasons. All callbacks, other than the [integration] and [memory management] functions, include a unique context identifier as the first parameter, From e5a26bd904d0fda4c7101b6bcb1a8909cdfc6830 Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Fri, 2 Aug 2024 17:47:15 -0400 Subject: [PATCH 23/28] review: add note about value of the parent context. Signed-off-by: Piotr Sikora --- abi-versions/v0.2.1/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/abi-versions/v0.2.1/README.md b/abi-versions/v0.2.1/README.md index fdfbd7c..69d6eaf 100644 --- a/abi-versions/v0.2.1/README.md +++ b/abi-versions/v0.2.1/README.md @@ -158,7 +158,8 @@ Returning `0` indicates failure. Called when the host creates a new context (`context_id`). When `parent_context_id` is `0` then a new plugin context is created, -otherwise a new per-stream context is created. +otherwise a new per-stream context is created and `parent_context_id` +refers to the plugin context. #### `proxy_on_done` From 76a339ddcd7e619a4d2f3e72844342a079c5edc1 Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Fri, 2 Aug 2024 17:47:46 -0400 Subject: [PATCH 24/28] review: add note about dynamic log level on the hosts. Signed-off-by: Piotr Sikora --- abi-versions/v0.2.1/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/abi-versions/v0.2.1/README.md b/abi-versions/v0.2.1/README.md index 69d6eaf..00bedbf 100644 --- a/abi-versions/v0.2.1/README.md +++ b/abi-versions/v0.2.1/README.md @@ -345,6 +345,11 @@ Retrieves host's current log level (`return_log_level`). This can be used to avoid creating log entries that are going to be discarded by the host. +> **Note** +> Hosts might change the log level at runtime, and currently there is +> no callback to notify the Wasm module about it, so `return_log_level` +> can become stale. + Returned `status` value is: - `OK` on success. - `INVALID_MEMORY_ACCESS` when `return_log_level` points to invalid From d5492305d73dce5e51375c332491ae465df0bd25 Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Fri, 2 Aug 2024 17:48:15 -0400 Subject: [PATCH 25/28] review: clarify it's a low-resolution timer. Signed-off-by: Piotr Sikora --- abi-versions/v0.2.1/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/abi-versions/v0.2.1/README.md b/abi-versions/v0.2.1/README.md index 00bedbf..b186588 100644 --- a/abi-versions/v0.2.1/README.md +++ b/abi-versions/v0.2.1/README.md @@ -417,10 +417,10 @@ Returned `errno` value is: * returns: - `i32 (`[`proxy_status_t`]`) status` -Sets timer period (`tick_period`). When set, the host will call -[`proxy_on_tick`] every `tick_period` milliseconds. +Sets a low-resolution timer period (`tick_period`). -Setting `tick_period` to `0` disables the timer. +When set, the host will call [`proxy_on_tick`] every `tick_period` +milliseconds. Setting `tick_period` to `0` disables the timer. Returned `status` value is: - `OK` on success. From d2df35a5b7ef97ce5e035db954bffb79fb2bb694 Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Fri, 2 Aug 2024 17:48:36 -0400 Subject: [PATCH 26/28] review: document peer_type. Signed-off-by: Piotr Sikora --- abi-versions/v0.2.1/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/abi-versions/v0.2.1/README.md b/abi-versions/v0.2.1/README.md index b186588..5384e47 100644 --- a/abi-versions/v0.2.1/README.md +++ b/abi-versions/v0.2.1/README.md @@ -898,6 +898,9 @@ Plugin must return one of the following values: Called when downstream connection is closed. +The `peer_type` should describe whether this was initiated by a `LOCAL` +or `REMOTE` peer, but this value might also be `UNKNOWN`. + #### `proxy_on_upstream_data` @@ -938,6 +941,9 @@ Plugin must return one of the following values: Called when upstream connection is closed. +The `peer_type` should describe whether this was initiated by a `LOCAL` +or `REMOTE` peer, but this value might also be `UNKNOWN`. + ## HTTP streams From cb29701131b175404b6126b2f26c8b7c33f22377 Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Fri, 2 Aug 2024 17:49:41 -0400 Subject: [PATCH 27/28] review: clarify the role of NULL character in serialized maps. Signed-off-by: Piotr Sikora --- abi-versions/v0.2.1/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/abi-versions/v0.2.1/README.md b/abi-versions/v0.2.1/README.md index 5384e47..e2cac03 100644 --- a/abi-versions/v0.2.1/README.md +++ b/abi-versions/v0.2.1/README.md @@ -1932,8 +1932,8 @@ This function is never called. Non-empty maps are serialized as: - 32-bit integer containing the number of keys in the map, - a series of pairs of 32-bit integers containing length of key and value, -- a series of pairs of bytes containing key and value, separated by `NULL` - (`0x00`) character. +- a series of pairs of byte sequences containing key and value, with each + key and value byte sequence terminated by a `NULL` (`0x00`) character. e.g. the map `{{"a": "1"}, {"b": "22"}}` would be serialized as: - `0x02`, From bc8d17c1019fcfc73584addb08409c5cc2e20f23 Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Fri, 2 Aug 2024 17:50:13 -0400 Subject: [PATCH 28/28] review: add link to the spec from the README. Signed-off-by: Piotr Sikora --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 09b736f..77593f0 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,12 @@ Proxy-Wasm extensions across different proxies. [WebAssembly in Envoy]: docs/WebAssembly-in-Envoy.md +## Specification + +The latest and widely implemented version of the specification is [v0.2.1]. + +[v0.2.1]: abi-versions/v0.2.1/README.md + ## Implementations ### SDKs