Skip to content

router: add support for direct (non-proxied) http responses.#2335

Merged
mattklein123 merged 8 commits intoenvoyproxy:masterfrom
brian-pane:direct-response/2315
Jan 16, 2018
Merged

router: add support for direct (non-proxied) http responses.#2335
mattklein123 merged 8 commits intoenvoyproxy:masterfrom
brian-pane:direct-response/2315

Conversation

@brian-pane
Copy link
Copy Markdown
Contributor

Description:
This PR implements support for returning an HTTP response with a configured
status code without proxying to an upstream.

Risk Level: Medium

Limitations:
There are two features in the corresponding data-plane-api PR that are not implemented in this PR:

  • Sending an entity-body with the response
  • Sending the configured response_headers_to_add with the response

I plan to put those feature in a separate PR, in order to keep this PR manageably small.
There are TODO comments for them in this PR.

Testing: Updated unit and integration tests included

Docs Changes: N/A

Release Notes:
N/A (I'll add this feature to the release notes once I've added support for sending
a configured response body and headers.)

Fixes: #2315

API Changes:
envoyproxy/data-plane-api#393

Signed-off-by: Brian Pane bpane@pinterest.com

Brian Pane added 2 commits January 10, 2018 04:11
Signed-off-by: Brian Pane <bpane@pinterest.com>
Signed-off-by: Brian Pane <bpane@pinterest.com>
Copy link
Copy Markdown
Contributor

@alyssawilk alyssawilk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool, this will be a super useful feature to have!

a couple of drive by comments below

};

/**
* A routing primitive that specifies a direct (non-proxied) HTTP response .
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

response.

typedef std::unique_ptr<const Decorator> DecoratorConstPtr;

/**
* An interface that holds a RedirectEntry or a RouteEntry for a request.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer this replace RedirectEntry rather than be a slightly duplicate thing.
newPath could be optional, and expected for redirect responses. I'm neutral if it should be done here or in a follow-up but maybe add a TODO?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion; combining RedirectEntry and DirectResponseEntry sounds good to me. The combined code will have to deal with some incompatibilities between the two -- e.g., under the current data plane API, redirects aren't allowed to send the response_headers_to_add, whereas direct responses are required to -- but it will probably still be cleaner than the current diff.

I'll merge the implementations post an update to this PR later today.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool. hopefully if we do some sanity checks with an IsRedirectReturnCode() in the right places we'll guard against bad configs/code

Copy link
Copy Markdown
Member

@mattklein123 mattklein123 Jan 10, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see any reason redirects cannot also populate response_headers_to_add. That seems pretty useful to me. Thoughts?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding response_headers_to_add to redirects would change the behavior of existing configs. If we were designing the config schema from scratch, I’d advocate for sending the headers with redirects. But at this point it would impact backward compatibility. Unless we added a “send_headers_with_redirects” flag that defaults to false, I suppose :(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, fair enough. I kind of think we could "just do it" and document it in this case as a change. But that's me. Fine to block/TODO for now if you think that would be best.

virtual const RedirectEntry* redirectEntry() const PURE;

/**
* @return the direct response entry or nullptr if there is no direct response for the request.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@return DirectResponseEntry*

const DirectResponseEntry* RouteEntryImplBase::directResponseEntry() const {
// A route for a request can exclusively be a route entry, a direct response entry,
// or a redirect entry.
if (isDirectResponse()) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think this is confusing, since a redirect entry is a direct response too


// Add an additional route with a direct (non-proxied) response.
void addDirectResponse(const std::string& domains, const std::string& prefix,
Http::Code responseCode, const std::string& body);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think this will be used widely? If not I'd just suggest doing this as with void addConfigModifier(HttpModifierFunction function); in testRouterDirectResponse

Copy link
Copy Markdown
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 drive by comments. Thanks for working on this. I'm +1 on combining redirect and direct response somehow. I think it will make the code simpler.

throw EnvoyException("Redirect route entries must not have WebSockets set");
}
}
bool has_direct_response = false;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the v1 code can be dropped, right?

validateAndAppendKey(ret, datasource.inline_bytes());
break;
}
case envoy::api::v2::DataSource::kInlineString: {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove from this PR?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ll move this to a separate PR

Brian Pane added 2 commits January 11, 2018 04:23
Signed-off-by: Brian Pane <bpane@pinterest.com>
Signed-off-by: Brian Pane <bpane@pinterest.com>
@brian-pane
Copy link
Copy Markdown
Contributor Author

I'll add another commit later to address a couple of open review comments:

  • removing v1 API support
  • removing the new addDirectResponse utility function that's only used once in the test suite

Copy link
Copy Markdown
Contributor

@alyssawilk alyssawilk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking great - thanks for taking the time to extend/rename the redirect entry

if (route_->directResponseEntry()) {
auto response_code = route_->directResponseEntry()->responseCode();
if (response_code >= Http::Code::MultipleChoices && response_code < Http::Code::BadRequest) {
config_.stats_.rq_redirect_.inc();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we probably want a direct response stat which supplements (and hopefully eventually replaces) the redirect stat.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a counter of direct responses. Is there a precedent in Envoy for also having counters per response status or per response code family (2xx, 3xx, etc)?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have split out codes for all downstream responses. IMO that's probably sufficient.

response_code);
return Http::FilterHeadersStatus::StopIteration;
}
Http::Utility::sendLocalReply(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Take a look at callers of sendLocalReply - I think you can simplify the arguments a bit (and if I'm incorrect please educate me! :-P)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see, this method is in the same class that provides a friendly wrapper around sendLocalReply. I'll switch to that.

Brian Pane added 2 commits January 11, 2018 21:33
Signed-off-by: Brian Pane <bpane@pinterest.com>
Signed-off-by: Brian Pane <bpane@pinterest.com>
Copy link
Copy Markdown
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks solid, thanks. Few small comments.

"weighted_clusters": {"$ref" : "#/definitions/weighted_clusters"},
"host_redirect" : {"type" : "string"},
"path_redirect" : {"type" : "string"},
"status": {"type": "integer"},
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

del?


const DecoratorConstPtr decorator_;
const Http::Code redirect_response_code_;
const Http::Code direct_response_code_;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I might consider making this Optional<Http::Code>. I think it would be slightly clearer in all the places you set and consume it.

response_code);
return Http::FilterHeadersStatus::StopIteration;
}
config_.stats_.rq_direct_response_.inc();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add an expectation in one of the tests that checks this stat gets incremented.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, and I almost forgot - we should update docs for this. Please add an envoy-API pull updating router_filter.rst and note it in your PR description

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@brian-pane you plan on finishing up docs in a follow up, right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I was planning to make a followup PR that adds the remainder of this feature (adding optional response headers and body), with the docs linked to that new PR.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK that works. Will merge this.

Signed-off-by: Brian Pane <bpane@pinterest.com>
mattklein123
mattklein123 previously approved these changes Jan 12, 2018
Copy link
Copy Markdown
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thank you. Will defer to @alyssawilk for final review/merge. (She is out Fridays so probably Tuesday).

@PiotrSikora
Copy link
Copy Markdown
Contributor

Could you please add YAML tests?

@brian-pane
Copy link
Copy Markdown
Contributor Author

I'll add SAML tests and post an updated diff tomorrow

alyssawilk
alyssawilk previously approved these changes Jan 16, 2018
Copy link
Copy Markdown
Contributor

@alyssawilk alyssawilk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, Looks great to me :-)
Merge pending Piotr's sign off on tests.

Signed-off-by: Brian Pane <bpane@pinterest.com>
@brian-pane brian-pane dismissed stale reviews from alyssawilk and mattklein123 via e309720 January 16, 2018 21:05
@brian-pane
Copy link
Copy Markdown
Contributor Author

@PiotrSikora I added some YAML tests. Let me know if they look okay.

Copy link
Copy Markdown
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, thanks!

@mattklein123 mattklein123 merged commit a651288 into envoyproxy:master Jan 16, 2018
@brian-pane brian-pane deleted the direct-response/2315 branch January 22, 2018 22:47
Shikugawa pushed a commit to Shikugawa/envoy that referenced this pull request Mar 28, 2020
jpsim added a commit that referenced this pull request Nov 28, 2022
And include in GitHub release artifacts

Updates rules_swift to pull in
bazelbuild/rules_swift#838

When users open the archive, they'll have rich docs they can explore
using Xcode's documentation navigator.

When we update to Xcode 13.4, we'll be able to generate HTML docs with
this approach and publish to the documentation website. Here's a demo of
what that static site looks like:
https://envoy-mobile-docc-demo.netlify.app/documentation/envoy/

https://user-images.githubusercontent.com/474794/171704142-993072a3-fbc2-4db6-9c70-65e9e1a47aac.mp4

Risk Level: Low
Testing: Local, CI
Docs Changes: Added
Release Notes: Added

Signed-off-by: JP Simard <jp@jpsim.com>
jpsim added a commit that referenced this pull request Nov 29, 2022
And include in GitHub release artifacts

Updates rules_swift to pull in
bazelbuild/rules_swift#838

When users open the archive, they'll have rich docs they can explore
using Xcode's documentation navigator.

When we update to Xcode 13.4, we'll be able to generate HTML docs with
this approach and publish to the documentation website. Here's a demo of
what that static site looks like:
https://envoy-mobile-docc-demo.netlify.app/documentation/envoy/

https://user-images.githubusercontent.com/474794/171704142-993072a3-fbc2-4db6-9c70-65e9e1a47aac.mp4

Risk Level: Low
Testing: Local, CI
Docs Changes: Added
Release Notes: Added

Signed-off-by: JP Simard <jp@jpsim.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants