Skip to content

Commit

Permalink
feat(): support application/x-www-form-urlencoded
Browse files Browse the repository at this point in the history
  • Loading branch information
ncarlier committed May 9, 2022
1 parent 213a1c4 commit 173ba6c
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 23 deletions.
29 changes: 15 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@ $ docker run -d --name=webhookd \
webhookd --scripts=/var/opt/webhookd/scripts
```

> Note that this image extends `docker:dind` Docker image.
> Note: This image extends `docker:dind` Docker image.
> Therefore you are able to interact with a Docker daemon with yours shell scripts.
**Or** use APT:

Finally, it is possible to install Webhookd using the Debian packaging system through this [custom repository](https://packages.azlux.fr/).

> Note that custom configuration variables can be set into `/etc/webhookd.env` file.
> Note: Custom configuration variables can be set into `/etc/webhookd.env` file.
> Sytemd service is already set and enable, you just have to start it with `systemctl start webhookd`.
## Configuration
Expand Down Expand Up @@ -78,7 +78,7 @@ You can override the default using the `WHD_SCRIPTS` environment variable or `-s
|--> ...
```

Note that Webhookd is able to run any type of file in this directory as long as the file is executable.
> Note: Webhookd is able to run any type of file in this directory as long as the file is executable.
For example, you can execute a Node.js file if you give execution rights to the file and add the appropriate `#!` header (in this case: `#!/usr/bin/env node`).

You can find sample scripts in the [example folder](./scripts/examples).
Expand Down Expand Up @@ -139,15 +139,17 @@ data: bar bar bar

### Webhook parameters

You have several way to provide parameters to your webhook script:
You have several ways to provide parameters to your webhook script:

- URL query parameters and HTTP headers are converted into environment variables.
Variable names follows "snakecase" naming convention.
Therefore the name can be altered.
- URL request parameters are converted to script variables
- HTTP headers are converted to script variables
- Request body (depending the Media Type):
- `application/x-www-form-urlencoded`: keys and values are converted to script variables
- `text/*` or `application/json`: payload is transmit to the script as first parameter.

*ex: `CONTENT-TYPE` will become `content_type`.*

- When using `POST`, body content (text/plain or application/json) is transmit to the script as parameter.
> Note: Variable name follows "snakecase" naming convention.
Therefore the name can be altered.
*ex: `CONTENT-TYPE` will become `content_type`.*

*Example:*

Expand Down Expand Up @@ -226,7 +228,7 @@ $ # or
$ webhookd --notification-uri=http://requestb.in/v9b229v9
```

Note that only the output of the script prefixed by "notify:" is sent to the notification channel.
> Note: Only the output of the script prefixed by "notify:" is sent to the notification channel.
If the output does not contain a prefixed line, no notification will be sent.

**Example:**
Expand Down Expand Up @@ -261,7 +263,7 @@ The following JSON payload is POST to the target URL:
}
```

Note that because the payload have a `text` attribute, you can use a [Mattermost][mattermost], [Slack][slack] or [Discord][discord] webhook endpoint.
> Note: that because the payload have a `text` attribute, you can use a [Mattermost][mattermost], [Slack][slack] or [Discord][discord] webhook endpoint.
[mattermost]: https://docs.mattermost.com/developer/webhooks-incoming.html
[discord]: https://discord.com/developers/docs/resources/webhook#execute-slackcompatible-webhook
Expand Down Expand Up @@ -293,8 +295,7 @@ $ htpasswd -B -c .htpasswd api
```
This command will ask for a password and store it in the htpawsswd file.

Please note that by default, the daemon will try to load the `.htpasswd` file.

By default, the daemon will try to load the `.htpasswd` file.
But you can override this behavior by specifying the location of the file:

```bash
Expand Down
4 changes: 2 additions & 2 deletions pkg/api/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import (
"github.com/ncarlier/webhookd/pkg/strcase"
)

// QueryParamsToShellVars convert URL query parameters to shell vars.
func QueryParamsToShellVars(q url.Values) []string {
// URLValuesToShellVars convert URL values to shell vars.
func URLValuesToShellVars(q url.Values) []string {
var params []string
for k, v := range q {
var buf bytes.Buffer
Expand Down
27 changes: 21 additions & 6 deletions pkg/api/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"io"
"io/ioutil"
"mime"
"net/http"
"path"
"path/filepath"
Expand Down Expand Up @@ -51,7 +52,7 @@ func triggerWebhook(w http.ResponseWriter, r *http.Request) {
// Check that streaming is supported
flusher, ok := w.(http.Flusher)
if !ok {
http.Error(w, "Streaming not supported!", http.StatusInternalServerError)
http.Error(w, "streaming not supported", http.StatusInternalServerError)
return
}

Expand All @@ -68,14 +69,28 @@ func triggerWebhook(w http.ResponseWriter, r *http.Request) {
return
}

body, err := ioutil.ReadAll(r.Body)
if err != nil {
logger.Error.Printf("error reading body: %v", err)
http.Error(w, "can't read body", http.StatusBadRequest)
if err = r.ParseForm(); err != nil {
logger.Error.Printf("error reading from-data: %v", err)
http.Error(w, "unable to parse request form", http.StatusBadRequest)
return
}

params := QueryParamsToShellVars(r.URL.Query())
// parse body
var body []byte
ct := r.Header.Get("Content-Type")
if ct != "" {
mediatype, _, _ := mime.ParseMediaType(ct)
if strings.HasPrefix(mediatype, "text/") || mediatype == "application/json" {
body, err = ioutil.ReadAll(r.Body)
if err != nil {
logger.Error.Printf("error reading body: %v", err)
http.Error(w, "unable to read request body", http.StatusBadRequest)
return
}
}
}

params := URLValuesToShellVars(r.Form)
params = append(params, HTTPHeadersToShellVars(r.Header)...)

// logger.Debug.Printf("API REQUEST: \"%s\" with params %s...\n", p, params)
Expand Down
2 changes: 1 addition & 1 deletion pkg/api/test/helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func TestQueryParamsToShellVars(t *testing.T) {
"string": []string{"foo"},
"list": []string{"foo", "bar"},
}
values := api.QueryParamsToShellVars(tc)
values := api.URLValuesToShellVars(tc)
assert.ContainsStr(t, "string=foo", values, "")
assert.ContainsStr(t, "list=foo,bar", values, "")
}
Expand Down

0 comments on commit 173ba6c

Please sign in to comment.