-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Local reply mapper - implementation #8921
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
44762f6
2d14f71
54f3ff4
8d5bd74
525956e
2b3d7de
b71957b
84660a6
f9d6086
3e0d621
bdcaa07
be3a848
ed817a5
b4c82b6
b18f1cb
2407530
f4d9a07
613203d
7af677d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,6 +11,7 @@ import "envoy/api/v2/core/protocol.proto"; | |
| import "envoy/api/v2/rds.proto"; | ||
| import "envoy/api/v2/srds.proto"; | ||
| import "envoy/config/filter/accesslog/v2/accesslog.proto"; | ||
| import "envoy/type/format.proto"; | ||
| import "envoy/type/percent.proto"; | ||
|
|
||
| import "google/protobuf/any.proto"; | ||
|
|
@@ -24,7 +25,7 @@ import "validate/validate.proto"; | |
| // HTTP connection manager :ref:`configuration overview <config_http_conn_man>`. | ||
| // [#extension: envoy.filters.network.http_connection_manager] | ||
|
|
||
| // [#next-free-field: 36] | ||
| // [#next-free-field: 37] | ||
| message HttpConnectionManager { | ||
| enum CodecType { | ||
| // For every new connection, the connection manager will determine which | ||
|
|
@@ -468,6 +469,35 @@ message HttpConnectionManager { | |
| // with `prefix` match set to `/dir`. Defaults to `false`. Note that slash merging is not part of | ||
| // `HTTP spec <https://tools.ietf.org/html/rfc3986>` and is provided for convenience. | ||
| bool merge_slashes = 33; | ||
|
|
||
| // Configuration of local reply returned by Envoy. Allows to specify mappings and format of | ||
| // response. | ||
| LocalReplyConfig local_reply_config = 36; | ||
| } | ||
|
|
||
| message LocalReplyConfig { | ||
| // Configuration of list of mappers which allows to filter and change local response. | ||
| // The client will iterate through mappers until first match. | ||
| repeated ResponseMapper mapper = 1; | ||
|
|
||
| // Allows to define custom format of local reply. | ||
| // It is allowed to use :ref:`command operators <config_access_log_command_operators>` | ||
| // which will be resolved to actual data. | ||
| type.StringOrJson format = 2; | ||
| } | ||
|
|
||
| message ResponseMapper { | ||
| // Filter is used to determine if the response should be rewritten. | ||
| accesslog.v2.AccessLogFilter filter = 1 [(validate.rules).message = {required: true}]; | ||
|
|
||
| // Rewriter defines how to rewrite determined response. | ||
| ResponseRewriter rewriter = 2 [(validate.rules).message = {required: true}]; | ||
| } | ||
|
|
||
| // Configuration of new value for matched local response. | ||
| message ResponseRewriter { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should there be an ability to override header values?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It might be added later.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agree. |
||
| // Status code for matched response. | ||
| google.protobuf.UInt32Value status_code = 1; | ||
| } | ||
|
|
||
| message Rds { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| syntax = "proto3"; | ||
|
|
||
| package envoy.type; | ||
|
|
||
| option java_outer_classname = "FormatProto"; | ||
| option java_multiple_files = true; | ||
| option java_package = "io.envoyproxy.envoy.type"; | ||
|
|
||
| import "google/protobuf/struct.proto"; | ||
|
|
||
| // [#protodoc-title: Format] | ||
|
|
||
| // Allows to define one of format: flat plain text or structured json. | ||
| message StringOrJson { | ||
| oneof format { | ||
| // Allows to specify flat plain text format. | ||
| // | ||
| // .. code-block:: yaml | ||
| // | ||
| // string_format: "My custom message" | ||
| // | ||
| string string_format = 1; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should this field be
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, it looks like
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess one reasonable question is "which API fields in general should be data sources?". Do we have a governing principle? Is it basically anything you might want to load from a disk? Do you have a concrete needs for this @euroelessar?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
We want an ability to return custom hard-coded user-facing html page on errors generated by envoy. Combination of this two factors implies that we need an ability to return potentially large binary body. To clarify, I'm fine with it not being part of this particular pull request, we can contribute the necessary pieces as follow ups, assuming the API can be extended to this needs.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would be nice to get the API clean here, what you're asking for isn't unreasonable. The actual code to consume from data source is a 1 liner, so if folks are in agreement let's do this. |
||
|
|
||
| // Allows to specify structured data as json. | ||
| // | ||
| // .. code-block:: yaml | ||
| // | ||
| // json_format: | ||
| // protocol: "HTTP/1.1" | ||
| // message: "My message" | ||
| // | ||
| // The following JSON object would be created: | ||
| // | ||
| // .. code-block:: json | ||
| // | ||
| // { | ||
| // "protocol": "HTTP/1.1", | ||
| // "message": "My message" | ||
| // } | ||
| // | ||
| google.protobuf.Struct json_format = 2; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| syntax = "proto3"; | ||
|
|
||
| package envoy.type.v3alpha; | ||
|
|
||
| option java_outer_classname = "FormatProto"; | ||
| option java_multiple_files = true; | ||
| option java_package = "io.envoyproxy.envoy.type.v3alpha"; | ||
|
|
||
| import "google/protobuf/struct.proto"; | ||
|
|
||
| // [#protodoc-title: Format] | ||
|
|
||
| // Allows to define one of format: flat plain text or structured json. | ||
| message StringOrJson { | ||
| oneof format { | ||
| // Allows to specify flat plain text format. | ||
| // | ||
| // .. code-block:: yaml | ||
| // | ||
| // string_format: "My custom message" | ||
| // | ||
| string string_format = 1; | ||
|
|
||
| // Allows to specify structured data as json. | ||
| // | ||
| // .. code-block:: yaml | ||
| // | ||
| // json_format: | ||
| // protocol: "HTTP/1.1" | ||
| // message: "My message" | ||
| // | ||
| // The following JSON object would be created: | ||
| // | ||
| // .. code-block:: json | ||
| // | ||
| // { | ||
| // "protocol": "HTTP/1.1", | ||
| // "message": "My message" | ||
| // } | ||
| // | ||
| google.protobuf.Struct json_format = 2; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,6 +12,7 @@ HTTP connection manager | |
| header_casing | ||
| headers | ||
| header_sanitizing | ||
| local_reply | ||
| stats | ||
| runtime | ||
| rds | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| .. _config_http_conn_man_local_reply: | ||
|
|
||
| Local reply modification | ||
| ======================== | ||
|
|
||
| The :ref:`HTTP connection manager <arch_overview_http_conn_man>` supports modification of local reply which is response returned by Envoy itself. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: "which is the response" |
||
|
|
||
| Features: | ||
|
|
||
| * :ref:`Local reply content modification<config_http_conn_man_local_reply_modification>`. | ||
| * :ref:`Local reply format modification<config_http_conn_man_local_reply_format>`. | ||
|
|
||
| .. _config_http_conn_man_local_reply_modification: | ||
|
|
||
| Local reply content modification | ||
| -------------------------------- | ||
|
|
||
| There is support for modification of local replies. You can specify list of :ref:`mappers <envoy_api_field_config.filter.network.http_connection_manager.v2.LocalReplyConfig.mapper>` which contains | ||
| pairs of :ref:`filter <envoy_api_msg_config.filter.accesslog.v2.AccessLogFilter>` and :ref:`rewriter <envoy_api_msg_config.filter.network.http_connection_manager.v2.ResponseRewriter>`. Both elements in pair has to be | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: "Both elements in the pair have to be specified." |
||
| specified. If more than one pair is defined then first matching is used. | ||
|
|
||
| Example how to change status code when local reply contains any of these response flags: | ||
|
|
||
| .. code-block:: yaml | ||
|
|
||
| mapper: | ||
| filter: | ||
| response_flag_filter: | ||
| flags: | ||
| - LH | ||
| - UH | ||
| rewriter: | ||
| status_code: 504 | ||
|
|
||
| .. _config_http_conn_man_local_reply_format: | ||
|
|
||
| Local reply format modification | ||
| ------------------------------- | ||
|
|
||
| Local reply format contains command operators that extract the relevant data and insert it. | ||
| They support two formats: :ref:`format strings <config_http_conn_man_local_reply_format_string>` and | ||
| :ref:`"format dictionaries" <config_http_conn_man_local_reply_dictionaries>`. In both cases, the :ref:`command operators <config_http_conn_man_local_reply_command_operators>` | ||
| are used to extract the relevant data, which is then inserted into the specified reply format. | ||
| Only one reply format may be specified at the time. | ||
|
|
||
| .. _config_http_conn_man_local_reply_format_string: | ||
|
|
||
| Format Strings | ||
| -------------- | ||
|
|
||
| Format strings are plain strings, specified using the ``format`` key. They may contain | ||
| either :ref:`command operators <config_http_conn_man_local_reply_command_operators>` or other characters interpreted as a plain string. | ||
| The access log formatter does not make any assumptions about a new line separator, so one | ||
| has to specified as part of the format string. | ||
|
|
||
| .. code-block:: none | ||
|
|
||
| %RESP_BODY% %RESPONSE_CODE% %RESPONSE_FLAGS% "My custom response" | ||
|
|
||
| Example of custom Envoy local reply format: | ||
|
|
||
| .. code-block:: none | ||
|
|
||
| upstream connect error or disconnect/reset before headers. reset reason: connection failure 204 UH My custom response | ||
|
|
||
|
|
||
| If format isn't specified then :ref:`default format <config_http_conn_man_local_reply_default_format>` is used. | ||
|
|
||
| .. _config_http_conn_man_local_reply_default_format: | ||
|
|
||
| Default Format String | ||
| --------------------- | ||
|
|
||
| If custom format string is not specified, Envoy uses the following default format: | ||
|
|
||
| .. code-block:: none | ||
|
|
||
| %RESP_BODY% | ||
|
|
||
| Example of the default local reply format: | ||
|
|
||
| .. code-block:: none | ||
|
|
||
| upstream connect error or disconnect/reset before headers. reset reason: connection failure | ||
|
|
||
| .. _config_http_conn_man_local_reply_dictionaries: | ||
|
|
||
| Format Dictionaries | ||
| ------------------- | ||
|
|
||
| Format dictionaries are dictionaries that specify a structured local reply output format, | ||
| specified using the ``json_format`` key. This allows response to be returned in a structured format | ||
| such as JSON. | ||
|
|
||
| More can be found in :ref:`configuration <config_access_log_format_dictionaries>`. | ||
|
|
||
| .. _config_http_conn_man_local_reply_command_operators: | ||
|
|
||
| Command Operators | ||
| ----------------- | ||
|
|
||
| Local reply format reuse :ref:`access log operators <config_access_log_command_operators>`, so more information can be found there. | ||
| It is also possible to use new command operator provided only for local reply modification purpose. | ||
|
|
||
| %RESP_BODY% | ||
| HTTP response body generated by Envoy. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can the
formatbe on per mapper basis, please?Example: we want to return different body and/or content type depending on the generated status code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
During config proposition we aggred that this might be added later. So I might add it in next PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have read the comments for prior version of pull request. It resolves the comment so no concerns from my side here.