caddyhttp: Implement handler abort; new 'abort' directive (close #3871) (#3983)

* caddyhttp: Implement handler abort; new 'abort' directive (close #3871)

* Move abort directive ordering; clean up redirects

Seems logical for the end-all of handlers to go at the... end.

The Connection header no longer needs to be set there, since Close is
true, and the static_response handler now does that.
This commit is contained in:
Matt Holt 2021-01-28 12:54:55 -07:00 committed by GitHub
parent ab80ff4fd2
commit e2c5c28597
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 27 additions and 4 deletions

View File

@ -40,6 +40,7 @@ func init() {
RegisterHandlerDirective("root", parseRoot)
RegisterHandlerDirective("redir", parseRedir)
RegisterHandlerDirective("respond", parseRespond)
RegisterHandlerDirective("abort", parseAbort)
RegisterHandlerDirective("route", parseRoute)
RegisterHandlerDirective("handle", parseHandle)
RegisterDirective("handle_errors", parseHandleErrors)
@ -502,6 +503,15 @@ func parseRespond(h Helper) (caddyhttp.MiddlewareHandler, error) {
return sr, nil
}
// parseAbort parses the abort directive.
func parseAbort(h Helper) (caddyhttp.MiddlewareHandler, error) {
h.Next() // consume directive
for h.Next() || h.NextBlock(0) {
return nil, h.ArgErr()
}
return &caddyhttp.StaticResponse{Abort: true}, nil
}
// parseRoute parses the route directive.
func parseRoute(h Helper) (caddyhttp.MiddlewareHandler, error) {
sr := new(caddyhttp.Subroute)

View File

@ -69,6 +69,7 @@ var directiveOrder = []string{
"php_fastcgi",
"file_server",
"acme_server",
"abort",
}
// directiveIsOrdered returns true if dir is

View File

@ -409,8 +409,7 @@ func (app *App) makeRedirRoute(redirToPort uint, matcherSet MatcherSet) Route {
StaticResponse{
StatusCode: WeakString(strconv.Itoa(http.StatusPermanentRedirect)),
Headers: http.Header{
"Location": []string{redirTo},
"Connection": []string{"close"},
"Location": []string{redirTo},
},
Close: true,
},

View File

@ -42,6 +42,11 @@ type StaticResponse struct {
// If true, the server will close the client's connection
// after writing the response.
Close bool `json:"close,omitempty"`
// Immediately and forcefully closes the connection without
// writing a response. Interrupts any other HTTP streams on
// the same connection.
Abort bool `json:"abort,omitempty"`
}
// CaddyModule returns the Caddy module information.
@ -101,10 +106,18 @@ func (s *StaticResponse) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
}
func (s StaticResponse) ServeHTTP(w http.ResponseWriter, r *http.Request, _ Handler) error {
repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
// close the connection immediately
if s.Abort {
panic(http.ErrAbortHandler)
}
// close the connection after responding
r.Close = s.Close
if s.Close {
r.Close = true
w.Header().Set("Connection", "close")
}
repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
// set all headers
for field, vals := range s.Headers {