Local reply mapper - implementation#8921
Local reply mapper - implementation#8921lukidzi wants to merge 19 commits intoenvoyproxy:masterfrom lukidzi:local_reply_mapper_impl
Conversation
Signed-off-by: Lukasz Dziedziak <lukasz.dziedziak@allegro.pl>
Signed-off-by: Lukasz Dziedziak <lukasz.dziedziak@allegro.pl>
htuch
left a comment
There was a problem hiding this comment.
Awesome, some comments to kick this off. Tests will be required; I think you can start work on integration tests without further feedback, since these will look the same regardless of implementation. API looks good, as previously agreed.
/wait
| } | ||
| } | ||
|
|
||
| // [#next-major-version: In the v3 API, we should consider renaming |
There was a problem hiding this comment.
Nit: please stick to 110 character line lengths, so this shouldn't wrap.
| // `HTTP spec <https://tools.ietf.org/html/rfc3986>` and is provided for convenience. | ||
| bool merge_slashes = 33; | ||
|
|
||
| // [#not-implemented-hide:] |
There was a problem hiding this comment.
Please uncomment if you are going to land this in this PR.
source/common/http/utility.cc
Outdated
| } | ||
|
|
||
| void Utility::sendLocalReply( | ||
| bool is_grpc, std::function<void(HeaderMapPtr&& headers, bool end_stream)> encode_headers, |
There was a problem hiding this comment.
This method signature keeps growing and growing :) Can we wrap the parameters up into one or more structs that group things together?
| } | ||
|
|
||
| ResponseMapper::ResponseMapper(AccessLog::FilterPtr&& filter, ResponseRewriterPtr&& rewriter) { | ||
| filter_ = std::move(filter); |
There was a problem hiding this comment.
Nit: prefer using initialization args.
| const StreamInfo::StreamInfo& stream_info) const { | ||
| const auto output_map = toMap(request_headers, response_headers, response_trailers, stream_info); | ||
| const StreamInfo::StreamInfo& stream_info, | ||
| const absl::string_view& body) const { |
There was a problem hiding this comment.
This only applies to locally generated responses, right? We don't have to worry about the remote having a 100MB response? What if someone specifies RESP_BODY on a regular access log formatter?
There was a problem hiding this comment.
Body is passed only for local_reply, for access log I'm passing empty string so this shouldn't be a problem.
There was a problem hiding this comment.
I think the direct response route action also goes through sendLocalReply. So, keep in mind that potentially largeish files could be present.
| // | ||
| // string_format: "My custom message" | ||
| // | ||
| string string_format = 1; |
There was a problem hiding this comment.
should this field be DataSource to allow fetching body from the control plane/disk?
There was a problem hiding this comment.
Actually, it looks like string_format assumes formatting.
In this case my ask is to add 3rd option with non-formattable DataSource.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Do you have a concrete needs for this @euroelessar?
We want an ability to return custom hard-coded user-facing html page on errors generated by envoy.
In addition to that we want to be able to serve compile-time compressed version of it for clients which support gzip/brotli.
Combination of this two factors implies that we need an ability to return potentially large binary body.
Adding this bodies to the config itself is potentially non-practical, therefore the ask for DataSource.
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.
There was a problem hiding this comment.
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.
| } | ||
|
|
||
| // Configuration of new value for matched local response. | ||
| message ResponseRewriter { |
There was a problem hiding this comment.
Should there be an ability to override header values?
For example to set content-type or some application-specific chillout header.
There was a problem hiding this comment.
It might be added later.
| // 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; |
There was a problem hiding this comment.
Can the format be 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.
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.
Have read the comments for prior version of pull request. It resolves the comment so no concerns from my side here.
| // | ||
| // string_format: "My custom message" | ||
| // | ||
| string string_format = 1; |
There was a problem hiding this comment.
Actually, it looks like string_format assumes formatting.
In this case my ask is to add 3rd option with non-formattable DataSource.
Signed-off-by: Lukasz Dziedziak <lukasz.dziedziak@allegro.pl>
Signed-off-by: Lukasz Dziedziak <lukidzi@gmail.com>
Signed-off-by: Lukasz Dziedziak <lukasz.dziedziak@allegro.pl>
Signed-off-by: Lukasz Dziedziak <lukasz.dziedziak@allegro.pl>
|
@lukidzi can you fix format and merge master? Is this ready for full review? Thank you. /wait |
|
I'm working on docs so I'll write when it's ready : ) |
Signed-off-by: Lukasz Dziedziak <lukasz.dziedziak@allegro.pl>
Signed-off-by: Lukasz Dziedziak <lukasz.dziedziak@allegro.pl>
Signed-off-by: Lukasz Dziedziak <lukasz.dziedziak@allegro.pl>
Signed-off-by: Lukasz Dziedziak <lukasz.dziedziak@allegro.pl>
alyssawilk
left a comment
There was a problem hiding this comment.
One discussion point while you're doing clean-up...
|
|
||
| struct LocalReplyData { | ||
| // Tells if this is a response to a gRPC request. | ||
| bool is_grpc_; |
There was a problem hiding this comment.
As long as we're doing an invasive refactor here, I wonder if we want to keep these special cased, or clean this up as well.
Arguably sendLocalReply could use request headers to determine is grpc and is head request. Or we could rewrite the two special cases we have as modification functions rather than preserving them as hard-coded one off special cases.
@mattklein123 any thoughts here?
Signed-off-by: Lukasz Dziedziak <lukasz.dziedziak@allegro.pl>
Signed-off-by: Lukasz Dziedziak <lukasz.dziedziak@allegro.pl>
Signed-off-by: Lukasz Dziedziak <lukasz.dziedziak@allegro.pl>
Signed-off-by: Lukasz Dziedziak <lukasz.dziedziak@allegro.pl>
Signed-off-by: Lukasz Dziedziak <lukasz.dziedziak@allegro.pl>
Signed-off-by: Lukasz Dziedziak <lukasz.dziedziak@allegro.pl>
|
@lukidzi can you ping the reviewers on this PR when this is ready for another pass? It's a bit unclear with the current activity whether reviewer feedback is addressed. |
|
I think it is ready for first review. I am trying to fix asan build but maybe you will see something that I missed. @htuch @alyssawilk @mattklein123 |
htuch
left a comment
There was a problem hiding this comment.
Generally looks good, I'm curious to see if we can get a fuzzer also in this PR.
| 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. |
| -------------------------------- | ||
|
|
||
| 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 |
There was a problem hiding this comment.
Nit: "Both elements in the pair have to be specified."
| CodeUtility::toString(Http::Code::InternalServerError), absl::nullopt, | ||
| parent_.is_head_request_); | ||
| parent_.state_.destroyed_, | ||
| Utility::EncodeFunctions{[&](HeaderMapPtr&& response_headers, bool end_stream) -> void { |
There was a problem hiding this comment.
Nit: this isn't your code, but if you can remove the wildcard & capture here, all the better.
| response_headers->setReferenceContentType(Headers::get().ContentTypeValues.Text); | ||
| HeaderMapPtr response_headers{new HeaderMapImpl{ | ||
| {Headers::get().Status, std::to_string(enumToInt(local_reply_data.response_code_))}}}; | ||
| std::string formatted_body{}; |
|
This pull request has been automatically marked as stale because it has not had activity in the last 7 days. It will be closed in 7 days if no further activity occurs. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions! |
|
any progress?@lukidzi |
|
This pull request has been automatically marked as stale because it has not had activity in the last 7 days. It will be closed in 7 days if no further activity occurs. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions! |
|
This pull request has been automatically closed because it has not had activity in the last 14 days. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions! |
|
@lukidzi, friendly ping =) |
|
@lukidzi we need this feature, are you going to finish this? or you prefer someone else to take over? |
|
@mattklein123 @htuch can you re-open this PR? |
|
ok, sure. I will wait for a couple days then. |
|
cc @Augustyniak also ^ as you recently asked for this. |
This is implementation of local reply mapper with ability to change format of response to custom Json. I haven't written any docs yet because I want to ensure you are ok with implementation proposition.
Description: Allows to create custom mapper of response code based on filters. Filter based on response headers might not work because when there is local reply we don't have any response headers. Also added possibility to map response to custom
TextorJsonformat.Risk Level: Low
Testing: I will add after implementation proposition review.
Docs Changes:
Release Notes:
Fixes #7537
Follow up #8126