reverseproxy: Add handle_response blocks to reverse_proxy (#3710)#3712
reverseproxy: Add handle_response blocks to reverse_proxy (#3710)#3712maxatome wants to merge 2 commits intocaddyserver:masterfrom
handle_response blocks to reverse_proxy (#3710)#3712Conversation
f47fbf4 to
62eb124
Compare
mholt
left a comment
There was a problem hiding this comment.
Thanks for working on a PR!
I just did a quick high-level pass for starters. We shouldn't have to change the dispenser or remove the CaddyfileUnmarshaler interface...
I also noticed that with this approach -- and maybe I'm wrong, feel free to correct me -- only filters on a single status code or header value. That seems like a severe limitation; I think adding more status codes is easily doable but giving proper control over headers is going to need more consideration.
|
|
||
| // Interface guards | ||
| var ( | ||
| _ caddyfile.Unmarshaler = (*Handler)(nil) |
There was a problem hiding this comment.
Why is this no longer a caddyfile Unmarshaler? It needs to be if it is to be used to unmarshal the Caddyfile.
There was a problem hiding this comment.
I agree it's not exactly right (because reverse_proxy still need to be a caddyfile.Unmarshaler), but this was done because with those changes, httpcaddyfile.Helper is needed to do the parse chaining.
There was a problem hiding this comment.
Thanks @francislavoie, you are right.
@mholt if you tell me how to cope with the absence of httpcaddyfile.Helper in (*Handler).UnmarshalCaddyfile() (as I need this httpcaddyfile.Helper instance to call httpcaddyfile.ParseSegmentAsSubroute() as suggested by @francislavoie in #3707), I will be happy to change this.
There was a problem hiding this comment.
I did a bit more digging in the source, and actually, I think it's okay for reverse_proxy to not be a caddyfile.Unmarshaler.
This is because it's never used as a guest module to something else. Regular directives don't strictly need to be Unmarshalers because their parsing is handled by callbacks registered with RegisterHandlerDirective or RegisterDirective, and those are passed Helper.
Most directives that do implement caddyfile.Unmarshaler only do so for the registered callbacks to call UnmarshalCaddyfile, but that's not actually necessary.
It is necessary for guest modules (like proxy transports, log encoders, log filters, matchers, etc.) to be Unmarshaler because they are invoked by the parent module (i.e. actual directive parsers).
There was a problem hiding this comment.
It's good practice / conventional to implement that, so you can unmarshal it where necessary. But true, all a directive needs is an unmarshaling function, not necessarily to implement an interface. I strongly encourage keeping to that convention, especially for consistency.
There was a problem hiding this comment.
I understand @mholt but in this case I don't think it's possible since we actually need to use Helper all the way down the callchain for handle_response to work. Consider how handle and route work, this is the same kind of situation (except that it's nested within another directive this time, i.e. reverse_proxy).
There was a problem hiding this comment.
Any news on that topic?
| // WithDispenser returns a new instance based on d. All others Helper | ||
| // fields are copied, so typically maps are shared with this new instance. | ||
| func (h Helper) WithDispenser(d *caddyfile.Dispenser) Helper { | ||
| h.Dispenser = d | ||
| return h | ||
| } |
There was a problem hiding this comment.
I'm not entirely clear on why this is necessary?
There was a problem hiding this comment.
The problem is httpcaddyfile.ParseSegmentAsSubroute takes a Helper rather than a Dispenser, which makes it necessary to chain parsing for other directives. Here, we only want to pass a dispenser that only has the contents of the handle_response block so that it doesn't overrun its parsing. That's why the dispenser is being replaced.
There was a problem hiding this comment.
Thanks again @francislavoie, yes this simple method is to simplify code in such cases.
I pushed a change in But perhaps you want to be able to combine several headers/statuses for one handle_response? I applied the format you proposed in the original issue #3707 but maybe I misunderstood your proposition. Do you want a handle_response block be like: ? Meaning both Feel free to provide me a complete spec of what you want so we can go further. |
6ef80a9 to
f4eace2
Compare
|
Just a heads up, #3740 may change the way the parsing of |
Aren't the args consumed by |
f4eace2 to
165dcf7
Compare
165dcf7 to
5b5b63c
Compare
5b5b63c to
4a48c44
Compare
|
Sorry to come back so late on this.
@maxatome So I had a bit of a think 🤔 and I believe what we should do to make this more natural is to reuse the matcher syntax that we already have for this, so like: This would be done by storing the named matchers in a map which is then referenced when parsing the I think we could keep the existing approach where if you just need one matcher, you can put it inline, but for anything more complex you'd use a named matcher. One annoyance is that since response matchers aren't the same as request matchers, we can't quite share that parsing code. |
|
Also - if you don't have the time to finish this off, let me know and I'd be glad to take it over (you'll still get author credit) |
|
Hi @francislavoie thanks for your reply. |
No description provided.