diff --git a/api/envoy/extensions/filters/http/ext_proc/v3/ext_proc.proto b/api/envoy/extensions/filters/http/ext_proc/v3/ext_proc.proto index 52d9cd282792a..cef6d260f683f 100644 --- a/api/envoy/extensions/filters/http/ext_proc/v3/ext_proc.proto +++ b/api/envoy/extensions/filters/http/ext_proc/v3/ext_proc.proto @@ -59,8 +59,10 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // * Request body: If the body is present, the behavior depends on the // body send mode. In ``BUFFERED`` or ``BUFFERED_PARTIAL`` mode, the body is sent to the external // processor in a single message. In ``STREAMED`` or ``FULL_DUPLEX_STREAMED`` mode, the body will -// be split across multiple messages sent to the external processor. In ``NONE`` mode, the body -// will not be sent to the external processor. +// be split across multiple messages sent to the external processor. In ``GRPC`` mode, as each +// gRPC message arrives, it will be sent to the external processor (there will be exactly one +// gRPC message in each message sent to the external processor). In ``NONE`` mode, the body will +// not be sent to the external processor. // * Request trailers: Delivered if they are present and if the trailer mode is set // to ``SEND``. // * Response headers: Contains the headers from the HTTP response. Keep in mind @@ -208,9 +210,9 @@ message ExternalProcessor { // an error (subject to the processing mode) if the timer expires before a // matching response is received. There is no timeout when the filter is // running in observability mode or when the body send mode is - // ``FULL_DUPLEX_STREAMED``. Zero is a valid config which means the timer - // will be triggered immediately. If not configured, default is 200 - // milliseconds. + // ``FULL_DUPLEX_STREAMED`` or ``GRPC``. Zero is a valid config which means + // the timer will be triggered immediately. If not configured, default is + // 200 milliseconds. google.protobuf.Duration message_timeout = 7 [(validate.rules).duration = { lte {seconds: 3600} gte {} @@ -272,8 +274,8 @@ message ExternalProcessor { // without pausing on filter chain iteration. It is "Send and Go" mode that can be used // by external processor to observe the request's data and status. In this mode: // - // 1. Only ``STREAMED`` and ``NONE`` body processing modes are supported; for any other body - // processing mode, the body will not be sent. + // 1. Only ``STREAMED``, ``GRPC``, and ``NONE`` body processing modes are supported; for any + // other body processing mode, the body will not be sent. // // 2. External processor should not send back processing response, as any responses will be ignored. // This also means that diff --git a/api/envoy/extensions/filters/http/ext_proc/v3/processing_mode.proto b/api/envoy/extensions/filters/http/ext_proc/v3/processing_mode.proto index 5ad32af519f80..dbe45d687872e 100644 --- a/api/envoy/extensions/filters/http/ext_proc/v3/processing_mode.proto +++ b/api/envoy/extensions/filters/http/ext_proc/v3/processing_mode.proto @@ -108,6 +108,25 @@ message ProcessingMode { // * The client will stream the body chunks in the responses from the server to the upstream/downstream as they arrive. FULL_DUPLEX_STREAMED = 4; + + // [#not-implemented-hide:] + // A mode for gRPC traffic. This is similar to ``FULL_DUPLEX_STREAMED``, + // except that instead of sending raw chunks of the HTTP/2 DATA frames, + // the ext_proc client will de-frame the individual gRPC messages inside + // the HTTP/2 DATA frames, and as each message is de-framed, it will be + // sent to the ext_proc server as a :ref:`request_body + // ` + // or :ref:`response_body + // `. + // The ext_proc server will stream back individual gRPC messages in the + // :ref:`StreamedBodyResponse ` + // field, but the number of messages sent by the ext_proc server + // does not need to equal the number of messages sent by the data + // plane. This allows the ext_proc server to change the number of + // messages sent on the stream. + // In this mode, the client will send body and trailers to the server as + // they arrive. + GRPC = 5; } // How to handle the request header. Default is "SEND". diff --git a/api/envoy/service/ext_proc/v3/external_processor.proto b/api/envoy/service/ext_proc/v3/external_processor.proto index 406c5c195a2a7..b2853d38e0762 100644 --- a/api/envoy/service/ext_proc/v3/external_processor.proto +++ b/api/envoy/service/ext_proc/v3/external_processor.proto @@ -164,7 +164,7 @@ message ProcessingRequest { // the server must send back exactly one ProcessingResponse message. // * If it is set to ``FULL_DUPLEX_STREAMED``, the server must follow the API defined // for this mode to send the ProcessingResponse messages. -// [#next-free-field: 11] +// [#next-free-field: 12] message ProcessingResponse { // The response type that is sent by the server. oneof response { @@ -224,6 +224,19 @@ message ProcessingResponse { // is set to true. envoy.extensions.filters.http.ext_proc.v3.ProcessingMode mode_override = 9; + // [#not-implemented-hide:] + // Used only in ``FULL_DUPLEX_STREAMED`` and ``GRPC`` body send modes. + // Instructs the data plane to stop sending body data and to send a + // half-close on the ext_proc stream. The ext_proc server should then echo + // back all subsequent body contents as-is until it sees the client's + // half-close, at which point the ext_proc server can terminate the stream + // with an OK status. This provides a safe way for the ext_proc server + // to indicate that it does not need to see the rest of the stream; + // without this, the ext_proc server could not terminate the stream + // early, because it would wind up dropping any body contents that the + // client had already sent before it saw the ext_proc stream termination. + bool request_drain = 11; + // When ext_proc server receives a request message, in case it needs more // time to process the message, it sends back a ProcessingResponse message // with a new timeout value. When the data plane receives this response @@ -268,11 +281,27 @@ message HttpHeaders { message HttpBody { // The contents of the body in the HTTP request/response. Note that in // streaming mode multiple ``HttpBody`` messages may be sent. + // + // In ``GRPC`` body send mode, a separate ``HttpBody`` message will be + // sent for each message in the gRPC stream. bytes body = 1; // If ``true``, this will be the last ``HttpBody`` message that will be sent and no // trailers will be sent for the current request/response. bool end_of_stream = 2; + + // This field is used in ``GRPC`` body send mode when ``end_of_stream`` is + // true and ``body`` is empty. Those values would normally indicate an + // empty message on the stream with the end-of-stream bit set. + // However, if the half-close happens after the last message on the + // stream was already sent, then this field will be true to indicate an + // end-of-stream with *no* message (as opposed to an empty message). + bool end_of_stream_without_message = 3; + + // This field is used in ``GRPC`` body send mode to indicate whether + // the message is compressed. This will never be set to true by gRPC + // but may be set to true by a proxy like Envoy. + bool grpc_message_compressed = 4; } // This message is sent to the external server when the HTTP request and @@ -331,6 +360,8 @@ message CommonResponse { // // In other words, this response makes it possible to turn an HTTP GET // into a POST, PUT, or PATCH. + // + // Not supported if the body send mode is ``GRPC``. CONTINUE_AND_REPLACE = 1; } @@ -415,15 +446,34 @@ message HeaderMutation { repeated string remove_headers = 2; } -// The body response message corresponding to FULL_DUPLEX_STREAMED body mode. +// The body response message corresponding to ``FULL_DUPLEX_STREAMED`` or ``GRPC`` body modes. message StreamedBodyResponse { - // The body response chunk that will be passed to the upstream/downstream by the data plane. + // In ``FULL_DUPLEX_STREAMED`` body send mode, contains the body response chunk that will be + // passed to the upstream/downstream by the data plane. In ``GRPC`` body send mode, contains + // a serialized gRPC message to be passed to the upstream/downstream by the data plane. 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. + // Note that in ``GRPC`` body send mode, this allows the ext_proc + // server to tell the data plane to send a half close after a client + // message, which will result in discarding any other messages sent by + // the client application. bool end_of_stream = 2; + + // This field is used in ``GRPC`` body send mode when ``end_of_stream`` is + // true and ``body`` is empty. Those values would normally indicate an + // empty message on the stream with the end-of-stream bit set. + // However, if the half-close happens after the last message on the + // stream was already sent, then this field will be true to indicate an + // end-of-stream with *no* message (as opposed to an empty message). + bool end_of_stream_without_message = 3; + + // This field is used in ``GRPC`` body send mode to indicate whether + // the message is compressed. This will never be set to true by gRPC + // but may be set to true by a proxy like Envoy. + bool grpc_message_compressed = 4; } // This message specifies the body mutation the server sends to the data plane. @@ -433,19 +483,19 @@ message BodyMutation { // 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``. + // is not set to ``FULL_DUPLEX_STREAMED`` or ``GRPC``. 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``. + // is not set to ``FULL_DUPLEX_STREAMED`` or ``GRPC``. // Clear the corresponding body chunk. bool clear_body = 2; // Must be used when the corresponding ``BodySendMode`` in the // :ref:`processing_mode ` - // is set to ``FULL_DUPLEX_STREAMED``. + // is set to ``FULL_DUPLEX_STREAMED`` or ``GRPC``. StreamedBodyResponse streamed_response = 3 [(xds.annotations.v3.field_status).work_in_progress = true]; }