-
Notifications
You must be signed in to change notification settings - Fork 619
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
Implement custom noroute html response #398
Conversation
BTW, I added https://github.com/fabiolb/fabio/wiki/Contributing#developing, as it took me quite a while to find out how this works with Go. Might need some rewriting? |
Hi Tino, thanks for the contribution. I will have a look right away. Also, thanks for adding the Developing section to the Wiki. Your description is spot on! |
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.
In general, this looks OK. I think NoRouteHTMLPath
is a bit too clumsy for a name but can't come up with something better right now.
The final version would need to have an integration test in the proxy/http_integration_test.go
file.
However, I do think that we could generalize the approach a bit further. If the code would watch a path in consul then we could have multiple custom files, e.g.
/fabio/page/noroute.html
/fabio/page/404.html
/fabio/page/503.html
...
store
would then contain a map[string]string
where the key is the code and the value is the page.
If there is a page for that code or for noroute
then fabio should return that.
However, this becomes more difficult in the case of 404
and 503
from the upstream service since the response has already been copied to the client. Fabio would have to sniff the status code from the response stream to inject its own response. The httputil.ReverseProxy
doesn't provide proper hooks for that AFAIR but I would need to look. If not, then this would certainly be a larger change.
What we could do nevertheless is to prepare the configuration for that so that when the feature gets implemented users don't have to change things.
route/no_route.go
Outdated
"sync/atomic" | ||
) | ||
|
||
// HTML Wrapper struct so we can store the html string in an atomic.Value |
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.
You don't need this since you can store a string
in an atomic.Value
directly.
route/no_route.go
Outdated
value string | ||
} | ||
|
||
// html stores the no route html string |
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.
I usually add a comment after the value to indicate the type since it cannot be changed once it is set, .e.g.
var store atomic.Value // string
route/no_route.go
Outdated
// GetHTML returns the HTML for not found routes. The function is safe to be | ||
// called from multiple goroutines. | ||
func GetHTML() string { | ||
return store.Load().(HTML).value |
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.
This then becomes
return store.Load().(string)
route/no_route.go
Outdated
return store.Load().(HTML).value | ||
} | ||
|
||
// hmu guards the atomic writes in SetHTML. |
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.
An atomic.Value
is already synchronized. Therefore, you don't need a mutex here.
registry/static/backend.go
Outdated
// WatchNoRouteHTML implementation that reads the noroute html from a | ||
// noroute.html file if it exists | ||
func (b *be) WatchNoRouteHTML() chan string { | ||
data, err := ioutil.ReadFile("noroute.html") |
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.
noroute.html
is a magic value and would need to be configurable.
route/no_route.go
Outdated
@@ -0,0 +1,44 @@ | |||
package route |
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.
I would probably create a separate package for this since neither route
nor proxy
is a good place to keep this.
On the mutex part, I copied this from the route/table.go. Why is it needed there and not here? I held off on multiple custom error pages. In my view if you set an error code in the upstream service, you should also provide the content you want to serve, and fabio should not overwrite it. This page is just for when the complete service could not be found, and is in sync with the |
Re mutex: I guess you're referring to this: https://github.com/fabiolb/fabio/blob/master/route/table.go#L47-L56 The reason a mutex is required here is that it changes two things: the table and the metrics registry. I'll have a look at the rest today. |
Ah okay. I missed that. |
I decided not to add a default HTML message. Although I would like not to serve a browsers default 503/404 by default to humans, it took me too much effort to cleanly implement with templates how I had it in mind. Is this mergeable as-is, or do you need some more changes? If so, we can start to remove our nginx instances that are in front of fabio atm |
I’ll have a quick look today |
This looks fine except that the name is still bugging me because it is too specific. How about we call it I can do this or you can pick this up. I'd like to get this merged as well. |
What I suggested is a larger refactor. I'll pick that up myself later. I'm going to merge this and amend the code with some small cleanup. Thanks for this! |
i'm... at an utter loss here... i finally got consul k/v setup with html, but no matter what i do, it comes out as plaintext, w/
type headers regardless of what I try. is there some magic "front matter"-like top part of the k/v string i'm supposed to use?
any help vastly appreciated as we're trying to make a bigger move to nomad and fabio... |
For me I have an HTML snippet in the consul KV and Fabio returns appropriate headers.
|
thanks @tristanmorgan ! ooh, that totally worked for me. 🙏 |
PR for #56
Add default no route HTML? (Like all other servers do, but then styled a bit nicer :)My first contribution to a Go project, so let me know what can be done better!
If tests are need, for what should I write them?
Closes #56