Compare commits

..

9 Commits

Author SHA1 Message Date
Adnan Hajdarević aeacb6dac7 Merge pull request #24 from adnanh/development
added hook reload on USR1 signal
2015-03-31 22:14:47 +02:00
Adnan Hajdarevic 1039151a16 added hook reload on USR1 signal 2015-03-31 22:10:35 +02:00
Adnan Hajdarević db928228c8 bumping up the minor version 2015-03-30 15:33:15 +02:00
Adnan Hajdarević 6896a34aab Merge pull request #21 from kevinlebrun/master
Allow charset to be defined in Content-Type header
2015-03-30 00:22:29 +02:00
Kevin Le Brun 5f853d8aba Allow charset to be defined in Content-Type header
The payload couldn't be parsed when charset was present in the
`Content-Type` header. The content type should begin with the MIME type
so we now check if the content type starts with `application/json` or
`application/x-www-form-urlencoded`.

This closes #20
2015-03-29 20:01:56 +02:00
Adnan Hajdarević 12c48f87cb Merge pull request #19 from moorereason/test-json
Add tests for ParseJSONParameters
2015-03-21 10:28:20 +01:00
Adnan Hajdarević acf38c3210 Merge pull request #18 from moorereason/extract-tests
Add new tests for ExtractParameter
2015-03-21 10:26:36 +01:00
Cameron Moore d3f368cb8f Add tests for ParseJSONParameters
This commit adds 100% coverage to Hook.ParaseJSONParameters.
2015-03-20 23:22:30 -05:00
Cameron Moore 943bc258f7 Add new tests for ExtractParameter
This commit regains 100% coverage for ExtractParameter after changes
from commit 688483d.
2015-03-20 22:43:39 -05:00
2 changed files with 77 additions and 21 deletions
+26
View File
@@ -48,6 +48,8 @@ var extractParameterTests = []struct {
{"a.500.b", map[string]interface{}{"a": map[string]interface{}{"b": "z"}}, "", false}, // non-existent slice
{"a.501.b", map[string]interface{}{"a": []interface{}{map[string]interface{}{"b": "y"}, map[string]interface{}{"b": "z"}}}, "", false}, // non-existent slice index
{"a.502.b", map[string]interface{}{"a": []interface{}{}}, "", false}, // non-existent slice index
{"a.b.503", map[string]interface{}{"a": map[string]interface{}{"b": []interface{}{"x", "y", "z"}}}, "", false}, // trailing, non-existent slice index
{"a.b", interface{}("a"), "", false}, // non-map, non-slice input
}
func TestExtractParameter(t *testing.T) {
@@ -85,6 +87,30 @@ func TestArgumentGet(t *testing.T) {
}
}
var hookParseJSONParametersTests = []struct {
params []Argument
headers, query, payload *map[string]interface{}
rheaders, rquery, rpayload *map[string]interface{}
}{
{[]Argument{Argument{"header", "a"}}, &map[string]interface{}{"a": `{"b": "y"}`}, nil, nil, &map[string]interface{}{"a": map[string]interface{}{"b": "y"}}, nil, nil},
{[]Argument{Argument{"url", "a"}}, nil, &map[string]interface{}{"a": `{"b": "y"}`}, nil, nil, &map[string]interface{}{"a": map[string]interface{}{"b": "y"}}, nil},
{[]Argument{Argument{"payload", "a"}}, nil, nil, &map[string]interface{}{"a": `{"b": "y"}`}, nil, nil, &map[string]interface{}{"a": map[string]interface{}{"b": "y"}}},
{[]Argument{Argument{"header", "z"}}, &map[string]interface{}{"z": `{}`}, nil, nil, &map[string]interface{}{"z": map[string]interface{}{}}, nil, nil},
// failures
{[]Argument{Argument{"header", "z"}}, &map[string]interface{}{"z": ``}, nil, nil, &map[string]interface{}{"z": ``}, nil, nil}, // empty string
{[]Argument{Argument{"header", "y"}}, &map[string]interface{}{"X": `{}`}, nil, nil, &map[string]interface{}{"X": `{}`}, nil, nil}, // missing parameter
}
func TestHookParseJSONParameters(t *testing.T) {
for _, tt := range hookParseJSONParametersTests {
h := &Hook{JSONStringParameters: tt.params}
h.ParseJSONParameters(tt.headers, tt.query, tt.payload)
if !reflect.DeepEqual(tt.headers, tt.rheaders) {
t.Errorf("failed to parse %v:\nexpected %#v,\ngot %#v", tt.params, *tt.rheaders, *tt.headers)
}
}
}
var hookExtractCommandArgumentsTests = []struct {
exec string
args []Argument
+40 -10
View File
@@ -10,7 +10,9 @@ import (
"net/url"
"os"
"os/exec"
"os/signal"
"strings"
"syscall"
"github.com/adnanh/webhook/hook"
@@ -21,7 +23,7 @@ import (
)
const (
version = "2.3.0"
version = "2.3.2"
)
var (
@@ -36,6 +38,7 @@ var (
key = flag.String("key", "key.pem", "path to the HTTPS certificate private key pem file")
watcher *fsnotify.Watcher
signals chan os.Signal
hooks hook.Hooks
)
@@ -54,6 +57,14 @@ func init() {
log.Println("version " + version + " starting")
// set os signal watcher
log.Printf("setting up os signal watcher\n")
signals = make(chan os.Signal, 1)
signal.Notify(signals, syscall.Signal(0xa))
go watchForSignals()
// load and parse hooks
log.Printf("attempting to load hooks from %s\n", *hooksFilePath)
@@ -152,7 +163,7 @@ func hookHandler(w http.ResponseWriter, r *http.Request) {
contentType := r.Header.Get("Content-Type")
if contentType == "application/json" {
if strings.HasPrefix(contentType, "application/json") {
decoder := json.NewDecoder(strings.NewReader(string(body)))
decoder.UseNumber()
@@ -161,7 +172,7 @@ func hookHandler(w http.ResponseWriter, r *http.Request) {
if err != nil {
log.Printf("error parsing JSON payload %+v\n", err)
}
} else if contentType == "application/x-www-form-urlencoded" {
} else if strings.HasPrefix(contentType, "application/x-www-form-urlencoded") {
fd, err := url.ParseQuery(string(body))
if err != nil {
log.Printf("error parsing form payload %+v\n", err)
@@ -206,13 +217,7 @@ func handleHook(hook *hook.Hook, headers, query, payload *map[string]interface{}
}
}
func watchForFileChange() {
for {
select {
case event := <-(*watcher).Events:
if event.Op&fsnotify.Write == fsnotify.Write {
log.Println("hooks file modified")
func reloadHooks() {
newHooks := hook.Hooks{}
// parse and swap
@@ -232,12 +237,37 @@ func watchForFileChange() {
hooks = newHooks
}
}
func watchForFileChange() {
for {
select {
case event := <-(*watcher).Events:
if event.Op&fsnotify.Write == fsnotify.Write {
log.Println("hooks file modified")
reloadHooks()
}
case err := <-(*watcher).Errors:
log.Println("watcher error:", err)
}
}
}
func watchForSignals() {
log.Println("os signal watcher ready")
for {
sig := <-signals
if sig == syscall.Signal(0xa) {
log.Println("caught USR1 signal")
reloadHooks()
} else {
log.Printf("caught unhandled signal %+v\n", sig)
}
}
}
// valuesToMap converts map[string][]string to a map[string]string object
func valuesToMap(values map[string][]string) map[string]interface{} {
ret := make(map[string]interface{})