Skip to content

Commit

Permalink
Merge pull request #107 from adnanh/development
Browse files Browse the repository at this point in the history
2.6.0
  • Loading branch information
adnanh authored Nov 1, 2016
2 parents 7d525cf + ecbcf11 commit b662166
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 37 deletions.
52 changes: 39 additions & 13 deletions hook/hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"errors"
"fmt"
"io/ioutil"
"net/textproto"
"reflect"
"regexp"
"strconv"
Expand All @@ -18,6 +19,7 @@ import (
const (
SourceHeader string = "header"
SourceQuery string = "url"
SourceQueryAlias string = "query"
SourcePayload string = "payload"
SourceString string = "string"
SourceEntirePayload string = "entire-payload"
Expand Down Expand Up @@ -205,11 +207,13 @@ type Argument struct {
// based on the Argument's source
func (ha *Argument) Get(headers, query, payload *map[string]interface{}) (string, bool) {
var source *map[string]interface{}
key := ha.Name

switch ha.Source {
case SourceHeader:
source = headers
case SourceQuery:
key = textproto.CanonicalMIMEHeaderKey(ha.Name)
case SourceQuery, SourceQueryAlias:
source = query
case SourcePayload:
source = payload
Expand Down Expand Up @@ -242,7 +246,7 @@ func (ha *Argument) Get(headers, query, payload *map[string]interface{}) (string
}

if source != nil {
return ExtractParameterAsString(ha.Name, *source)
return ExtractParameterAsString(key, *source)
}

return "", false
Expand Down Expand Up @@ -300,7 +304,9 @@ type Hook struct {

// ParseJSONParameters decodes specified arguments to JSON objects and replaces the
// string with the newly created object
func (h *Hook) ParseJSONParameters(headers, query, payload *map[string]interface{}) error {
func (h *Hook) ParseJSONParameters(headers, query, payload *map[string]interface{}) []error {
var errors = make([]error, 0)

for i := range h.JSONStringParameters {
if arg, ok := h.JSONStringParameters[i].Get(headers, query, payload); ok {
var newArg map[string]interface{}
Expand All @@ -311,7 +317,8 @@ func (h *Hook) ParseJSONParameters(headers, query, payload *map[string]interface
err := decoder.Decode(&newArg)

if err != nil {
return &ParseError{err}
errors = append(errors, &ParseError{err})
continue
}

var source *map[string]interface{}
Expand All @@ -321,27 +328,38 @@ func (h *Hook) ParseJSONParameters(headers, query, payload *map[string]interface
source = headers
case SourcePayload:
source = payload
case SourceQuery:
case SourceQuery, SourceQueryAlias:
source = query
}

if source != nil {
ReplaceParameter(h.JSONStringParameters[i].Name, source, newArg)
key := h.JSONStringParameters[i].Name

if h.JSONStringParameters[i].Source == SourceHeader {
key = textproto.CanonicalMIMEHeaderKey(h.JSONStringParameters[i].Name)
}

ReplaceParameter(key, source, newArg)
} else {
return &SourceError{h.JSONStringParameters[i]}
errors = append(errors, &SourceError{h.JSONStringParameters[i]})
}
} else {
return &ArgumentError{h.JSONStringParameters[i]}
errors = append(errors, &ArgumentError{h.JSONStringParameters[i]})
}
}

if len(errors) > 0 {
return errors
}

return nil
}

// ExtractCommandArguments creates a list of arguments, based on the
// PassArgumentsToCommand property that is ready to be used with exec.Command()
func (h *Hook) ExtractCommandArguments(headers, query, payload *map[string]interface{}) ([]string, error) {
func (h *Hook) ExtractCommandArguments(headers, query, payload *map[string]interface{}) ([]string, []error) {
var args = make([]string, 0)
var errors = make([]error, 0)

args = append(args, h.ExecuteCommand)

Expand All @@ -350,19 +368,23 @@ func (h *Hook) ExtractCommandArguments(headers, query, payload *map[string]inter
args = append(args, arg)
} else {
args = append(args, "")
return args, &ArgumentError{h.PassArgumentsToCommand[i]}
errors = append(errors, &ArgumentError{h.PassArgumentsToCommand[i]})
}
}

if len(errors) > 0 {
return args, errors
}

return args, nil
}

// ExtractCommandArgumentsForEnv creates a list of arguments in key=value
// format, based on the PassEnvironmentToCommand property that is ready to be used
// with exec.Command().
func (h *Hook) ExtractCommandArgumentsForEnv(headers, query, payload *map[string]interface{}) ([]string, error) {
func (h *Hook) ExtractCommandArgumentsForEnv(headers, query, payload *map[string]interface{}) ([]string, []error) {
var args = make([]string, 0)

var errors = make([]error, 0)
for i := range h.PassEnvironmentToCommand {
if arg, ok := h.PassEnvironmentToCommand[i].Get(headers, query, payload); ok {
if h.PassEnvironmentToCommand[i].EnvName != "" {
Expand All @@ -373,10 +395,14 @@ func (h *Hook) ExtractCommandArgumentsForEnv(headers, query, payload *map[string
args = append(args, EnvNamespace+h.PassEnvironmentToCommand[i].Name+"="+arg)
}
} else {
return args, &ArgumentError{h.PassEnvironmentToCommand[i]}
errors = append(errors, &ArgumentError{h.PassEnvironmentToCommand[i]})
}
}

if len(errors) > 0 {
return args, errors
}

return args, nil
}

Expand Down
58 changes: 34 additions & 24 deletions webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,21 @@ import (
)

const (
version = "2.5.0"
version = "2.6.0"
)

var (
ip = flag.String("ip", "0.0.0.0", "ip the webhook should serve hooks on")
port = flag.Int("port", 9000, "port the webhook should serve hooks on")
verbose = flag.Bool("verbose", false, "show verbose output")
noPanic = flag.Bool("nopanic", false, "do not panic if hooks cannot be loaded when webhook is not running in verbose mode")
hotReload = flag.Bool("hotreload", false, "watch hooks file for changes and reload them automatically")
hooksFilePath = flag.String("hooks", "hooks.json", "path to the json file containing defined hooks the webhook should serve")
hooksURLPrefix = flag.String("urlprefix", "hooks", "url prefix to use for served hooks (protocol://yourserver:port/PREFIX/:hook-id)")
secure = flag.Bool("secure", false, "use HTTPS instead of HTTP")
cert = flag.String("cert", "cert.pem", "path to the HTTPS certificate pem file")
key = flag.String("key", "key.pem", "path to the HTTPS certificate private key pem file")
ip = flag.String("ip", "0.0.0.0", "ip the webhook should serve hooks on")
port = flag.Int("port", 9000, "port the webhook should serve hooks on")
verbose = flag.Bool("verbose", false, "show verbose output")
noPanic = flag.Bool("nopanic", false, "do not panic if hooks cannot be loaded when webhook is not running in verbose mode")
hotReload = flag.Bool("hotreload", false, "watch hooks file for changes and reload them automatically")
hooksFilePath = flag.String("hooks", "hooks.json", "path to the json file containing defined hooks the webhook should serve")
hooksURLPrefix = flag.String("urlprefix", "hooks", "url prefix to use for served hooks (protocol://yourserver:port/PREFIX/:hook-id)")
secure = flag.Bool("secure", false, "use HTTPS instead of HTTP")
cert = flag.String("cert", "cert.pem", "path to the HTTPS certificate pem file")
key = flag.String("key", "key.pem", "path to the HTTPS certificate private key pem file")
justDisplayVersion = flag.Bool("version", false, "display webhook version and quit")

responseHeaders hook.ResponseHeaders

Expand All @@ -51,6 +52,11 @@ func main() {

flag.Parse()

if *justDisplayVersion {
fmt.Println("webhook version " + version)
os.Exit(0)
}

log.SetPrefix("[webhook] ")
log.SetFlags(log.Ldate | log.Ltime)

Expand Down Expand Up @@ -191,12 +197,10 @@ func hookHandler(w http.ResponseWriter, r *http.Request) {
}

// handle hook
if err = matchedHook.ParseJSONParameters(&headers, &query, &payload); err != nil {
msg := fmt.Sprintf("error parsing JSON parameters: %s", err)
log.Printf(msg)
w.WriteHeader(http.StatusBadRequest)
fmt.Fprintf(w, "Unable to parse JSON parameters.")
return
if errors := matchedHook.ParseJSONParameters(&headers, &query, &payload); errors != nil {
for _, err := range errors {
log.Printf("error parsing JSON parameters: %s\n", err)
}
}

var ok bool
Expand Down Expand Up @@ -249,21 +253,27 @@ func hookHandler(w http.ResponseWriter, r *http.Request) {
}

func handleHook(h *hook.Hook, headers, query, payload *map[string]interface{}, body *[]byte) (string, error) {
var err error
var errors []error

cmd := exec.Command(h.ExecuteCommand)
cmd.Dir = h.CommandWorkingDirectory

cmd.Args, err = h.ExtractCommandArguments(headers, query, payload)
if err != nil {
log.Printf("error extracting command arguments: %s", err)
cmd.Args, errors = h.ExtractCommandArguments(headers, query, payload)
if errors != nil {
for _, err := range errors {
log.Printf("error extracting command arguments: %s\n", err)
}
}

var envs []string
envs, err = h.ExtractCommandArgumentsForEnv(headers, query, payload)
if err != nil {
log.Printf("error extracting command arguments for environment: %s", err)
envs, errors = h.ExtractCommandArgumentsForEnv(headers, query, payload)

if errors != nil {
for _, err := range errors {
log.Printf("error extracting command arguments for environment: %s\n", err)
}
}

cmd.Env = append(os.Environ(), envs...)

log.Printf("executing %s (%s) with arguments %q and environment %s using %s as cwd\n", h.ExecuteCommand, cmd.Path, cmd.Args, envs, cmd.Dir)
Expand Down

0 comments on commit b662166

Please sign in to comment.