Skip to content
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

Allow requests to pass through exec middleware #19

Merged
merged 2 commits into from
Feb 17, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ exec [<matcher>] [<command> [<args...>]] {
log <log output module>
err_log <log output module>
foreground
pass_thru
startup
shutdown
}
Expand All @@ -41,6 +42,7 @@ exec [<matcher>] [<command> [<args...>]] {
- **log** - [Caddy log output module](https://caddyserver.com/docs/caddyfile/directives/log#output-modules) for standard output log. Defaults to `stderr`.
- **err_log** - [Caddy log output module](https://caddyserver.com/docs/caddyfile/directives/log#output-modules) for standard error log. Defaults to the value of `log` (standard output log).
- **foreground** - if present, runs the command in the foreground. For commands at http endpoints, the command will exit before the http request is responded to.
- **pass_thru** - if present, enables pass-thru mode, which continues to the next HTTP handler in the route instead of responding directly
- **startup** - if present, run the command at startup. Ignored in routes.
- **shutdown** - if present, run the command at shutdown. Ignored in routes.

Expand Down Expand Up @@ -95,6 +97,8 @@ As a top level app for `startup` and `shutdown` commands.
"directory": "",
// [optional] if the command should run on the foreground. Default is false.
"foreground": false,
// [optional] if the middleware should respond directly or pass the request on to the next handler in the route. Default is false.
"pass_thru": false,
// [optional] timeout to terminate the command's process. Default is 10s.
"timeout": "10s",
// [optional] log output module config for standard output. Default is `stderr` module.
Expand Down Expand Up @@ -137,6 +141,8 @@ As an handler within a route.
"directory": "/home/user/site/public",
// [optional] if the command should run on the foreground. Default is false.
"foreground": true,
// [optional] if the middleware should respond directly or pass the request on to the next handler in the route. Default is false.
"pass_thru": true,
// [optional] timeout to terminate the command's process. Default is 10s.
"timeout": "5s",
// [optional] log output module config for standard output. Default is `stderr` module.
Expand Down
74 changes: 38 additions & 36 deletions caddyfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,18 @@ func newCommandFromDispenser(d *caddyfile.Dispenser) (cmd Cmd, err error) {
// parseHandlerCaddyfileBlock configures the handler directive from Caddyfile.
// Syntax:
//
// exec [<matcher>] [<command> [<args...>]] {
// command <text>
// args <text>...
// directory <text>
// timeout <duration>
// log <log output module>
// err_log <log output module>
// foreground
// startup
// shutdown
// }
//
// exec [<matcher>] [<command> [<args...>]] {
// command <text>
// args <text>...
// directory <text>
// timeout <duration>
// log <log output module>
// err_log <log output module>
// foreground
// pass_thru
// startup
// shutdown
// }
func parseHandlerCaddyfileBlock(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
cmd, err := newCommandFromDispenser(h.Dispenser)
return Middleware{Cmd: cmd}, err
Expand All @@ -43,18 +43,18 @@ func parseHandlerCaddyfileBlock(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHan
// parseGlobalCaddyfileBlock configures the "exec" global option from Caddyfile.
// Syntax:
//
// exec [<command> [<args...>]] {
// command <text>...
// args <text>...
// directory <text>
// timeout <duration>
// log <log output module>
// err_log <log output module>
// foreground
// startup
// shutdown
// }
//
// exec [<command> [<args...>]] {
// command <text>...
// args <text>...
// directory <text>
// timeout <duration>
// log <log output module>
// err_log <log output module>
// foreground
// pass_thru
// startup
// shutdown
// }
func parseGlobalCaddyfileBlock(d *caddyfile.Dispenser, prev interface{}) (interface{}, error) {
var exec App

Expand Down Expand Up @@ -91,18 +91,18 @@ func parseGlobalCaddyfileBlock(d *caddyfile.Dispenser, prev interface{}) (interf
// UnmarshalCaddyfile configures the handler directive from Caddyfile.
// Syntax:
//
// exec [<matcher>] [<command> [<args...>]] {
// command <text>
// args <text>...
// directory <text>
// timeout <duration>
// log <log output module>
// err_log <log output module>
// foreground
// startup
// shutdown
// }
//
// exec [<matcher>] [<command> [<args...>]] {
// command <text>
// args <text>...
// directory <text>
// timeout <duration>
// log <log output module>
// err_log <log output module>
// foreground
// pass_thru
// startup
// shutdown
// }
func (c *Cmd) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
// consume "exec", then grab the command, if present.
if d.NextArg() && d.NextArg() {
Expand Down Expand Up @@ -138,6 +138,8 @@ func (c *Cmd) unmarshalBlock(d *caddyfile.Dispenser) error {
}
case "foreground":
c.Foreground = true
case "pass_thru":
c.PassThru = true
case "startup":
c.At = append(c.At, "startup")
case "shutdown":
Expand Down
4 changes: 4 additions & 0 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ type Cmd struct {
// foreground may prevent Caddy from starting.
Foreground bool `json:"foreground,omitempty"`

// Enables pass-thru mode, which continues to the next HTTP
// handler in the route instead of responding directly
PassThru bool `json:"pass_thru,omitempty"`

// Timeout for the command. The command will be killed
// after timeout has elapsed if it is still running.
// Defaults to 10s.
Expand Down
18 changes: 13 additions & 5 deletions middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,6 @@ func (m Middleware) Validate() error { return m.Cmd.validate() }

// ServeHTTP implements caddyhttp.MiddlewareHandler.
func (m Middleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
var resp struct {
Status string `json:"status,omitempty"`
Error string `json:"error,omitempty"`
}

repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)

for index, argument := range m.Args {
Expand All @@ -53,6 +48,19 @@ func (m Middleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddy

err := m.run()

if m.PassThru {
if err != nil {
m.log.Error(err.Error())
}

return next.ServeHTTP(w, r)
}

var resp struct {
Status string `json:"status,omitempty"`
Error string `json:"error,omitempty"`
}

if err == nil {
resp.Status = "success"
} else {
Expand Down