From 6ac3cd177ba2d057ef46f309b71b8856ac176333 Mon Sep 17 00:00:00 2001 From: "update-envoy[bot]" <135279899+update-envoy[bot]@users.noreply.github.com> Date: Fri, 8 Nov 2024 20:32:34 +0000 Subject: [PATCH] Enhance ext_proc filter to support MXN streaming (#34942) This PR is for issue: https://github.com/envoyproxy/envoy/issues/32090. One of the use case is, like compression by the external processing. This is to let the ext_proc server be able to buffer M request body chunks from Envoy first, processing them, then send N chunks back to Envoy in the STREAMED mode. It also let the server buffer the entire message, i.e, header, body, trailer, before sending back any response. The ext_proc MXN streaming works this way: 1) Enable the MXN streaming by configuring the body mode to be FULL_DUPLEX_STREAMED in the ext_proc filter config. 2) Config the trailer mode to be SEND in the ext_proc filter config. With above config, Envoy will send body to the ext_proc server as they arrival. The server can buffer the entire or partial of the body (M chunks) then streaming the mutated body(may need to split into N chunks), back to Envoy. --------- Signed-off-by: Yanjun Xiang Mirrored from https://github.com/envoyproxy/envoy @ 72a20671ae70db520226388bfd351e817393d66e --- .../http/ext_proc/v3/processing_mode.proto | 34 ++++++++++++++++++- .../ext_proc/v3/external_processor.proto | 28 +++++++++++++-- 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/envoy/extensions/filters/http/ext_proc/v3/processing_mode.proto b/envoy/extensions/filters/http/ext_proc/v3/processing_mode.proto index 66c04acc..41403211 100644 --- a/envoy/extensions/filters/http/ext_proc/v3/processing_mode.proto +++ b/envoy/extensions/filters/http/ext_proc/v3/processing_mode.proto @@ -36,11 +36,12 @@ message ProcessingMode { // Control how the request and response bodies are handled // When body mutation by external processor is enabled, ext_proc filter will always remove - // the content length header in three cases below because content length can not be guaranteed + // the content length header in four cases below because content length can not be guaranteed // to be set correctly: // 1) STREAMED BodySendMode: header processing completes before body mutation comes back. // 2) BUFFERED_PARTIAL BodySendMode: body is buffered and could be injected in different phases. // 3) BUFFERED BodySendMode + SKIP HeaderSendMode: header processing (e.g., update content-length) is skipped. + // 4) FULL_DUPLEX_STREAMED BodySendMode: header processing completes before body mutation comes back. // // In Envoy's http1 codec implementation, removing content length will enable chunked transfer // encoding whenever feasible. The recipient (either client or server) must be able @@ -68,6 +69,37 @@ message ProcessingMode { // chunk. If the body exceeds the configured buffer limit, then the body contents // up to the buffer limit will be sent. BUFFERED_PARTIAL = 3; + + // [#not-implemented-hide:] + // Envoy streams the body to the server in pieces as they arrive. + // + // 1) The server may choose to buffer any number chunks of data before processing them. + // After it finishes buffering, the server processes the buffered data. Then it splits the processed + // data into any number of chunks, and streams them back to Envoy one by one. + // The server may continuously do so until the complete body is processed. + // The individual response chunk size is recommended to be no greater than 64K bytes, or + // :ref:`max_receive_message_length ` + // if EnvoyGrpc is used. + // + // 2) The server may also choose to buffer the entire message, including the headers (if header mode is + // ``SEND``), the entire body, and the trailers (if present), before sending back any response. + // The server response has to maintain the headers-body-trailers ordering. + // + // 3) Note that the server might also choose not to buffer data. That is, upon receiving a + // body request, it could process the data and send back a body response immediately. + // + // In this body mode: + // * The corresponding trailer mode has to be set to ``SEND``. + // * Envoy will send body and trailers (if present) to the server as they arrive. + // Sending the trailers (if present) is to inform the server the complete body arrives. + // In case there are no trailers, then Envoy will set + // :ref:`end_of_stream ` + // to true as part of the last body chunk request to notify the server that no other data is to be sent. + // * The server needs to send + // :ref:`StreamedBodyResponse ` + // to Envoy in the body response. + // * Envoy will stream the body chunks in the responses from the server to the upstream/downstream as they arrive. + FULL_DUPLEX_STREAMED = 4; } // How to handle the request header. Default is "SEND". diff --git a/envoy/service/ext_proc/v3/external_processor.proto b/envoy/service/ext_proc/v3/external_processor.proto index d1e5dcd7..ab193f49 100644 --- a/envoy/service/ext_proc/v3/external_processor.proto +++ b/envoy/service/ext_proc/v3/external_processor.proto @@ -377,15 +377,39 @@ message HeaderMutation { repeated string remove_headers = 2; } -// Replace the entire message body chunk received in the corresponding -// HttpBody message with this new body, or clear the body. +// [#not-implemented-hide:] +// The body response message corresponding to FULL_DUPLEX_STREAMED body mode. +message StreamedBodyResponse { + // The body response chunk that will be passed to the upstream/downstream by Envoy. + bytes body = 1; + + // The server sets this flag to true if it has received a body request with + // :ref:`end_of_stream ` set to true, + // and this is the last chunk of body responses. + bool end_of_stream = 2; +} + +// This message specifies the body mutation the server sends to Envoy. message BodyMutation { // The type of mutation for the body. oneof mutation { // The entire body to replace. + // Should only be used when the corresponding ``BodySendMode`` in the + // :ref:`processing_mode ` + // is not set to ``FULL_DUPLEX_STREAMED``. bytes body = 1; + // Clear the corresponding body chunk. + // Should only be used when the corresponding ``BodySendMode`` in the + // :ref:`processing_mode ` + // is not set to ``FULL_DUPLEX_STREAMED``. // Clear the corresponding body chunk. bool clear_body = 2; + + // [#not-implemented-hide:] + // Must be used when the corresponding ``BodySendMode`` in the + // :ref:`processing_mode ` + // is set to ``FULL_DUPLEX_STREAMED``. + StreamedBodyResponse streamed_response = 3; } }