mirror of
https://github.com/ncarlier/webhookd.git
synced 2025-04-20 16:18:00 +00:00
feat(): support application/x-www-form-urlencoded
This commit is contained in:
parent
213a1c4a29
commit
173ba6c347
29
README.md
29
README.md
|
@ -39,14 +39,14 @@ $ docker run -d --name=webhookd \
|
||||||
webhookd --scripts=/var/opt/webhookd/scripts
|
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.
|
> Therefore you are able to interact with a Docker daemon with yours shell scripts.
|
||||||
|
|
||||||
**Or** use APT:
|
**Or** use APT:
|
||||||
|
|
||||||
Finally, it is possible to install Webhookd using the Debian packaging system through this [custom repository](https://packages.azlux.fr/).
|
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`.
|
> Sytemd service is already set and enable, you just have to start it with `systemctl start webhookd`.
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
@ -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`).
|
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).
|
You can find sample scripts in the [example folder](./scripts/examples).
|
||||||
|
@ -139,15 +139,17 @@ data: bar bar bar
|
||||||
|
|
||||||
### Webhook parameters
|
### 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.
|
- URL request parameters are converted to script variables
|
||||||
Variable names follows "snakecase" naming convention.
|
- HTTP headers are converted to script variables
|
||||||
Therefore the name can be altered.
|
- 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`.*
|
> Note: Variable name follows "snakecase" naming convention.
|
||||||
|
Therefore the name can be altered.
|
||||||
- When using `POST`, body content (text/plain or application/json) is transmit to the script as parameter.
|
*ex: `CONTENT-TYPE` will become `content_type`.*
|
||||||
|
|
||||||
*Example:*
|
*Example:*
|
||||||
|
|
||||||
|
@ -226,7 +228,7 @@ $ # or
|
||||||
$ webhookd --notification-uri=http://requestb.in/v9b229v9
|
$ 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.
|
If the output does not contain a prefixed line, no notification will be sent.
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
@ -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
|
[mattermost]: https://docs.mattermost.com/developer/webhooks-incoming.html
|
||||||
[discord]: https://discord.com/developers/docs/resources/webhook#execute-slackcompatible-webhook
|
[discord]: https://discord.com/developers/docs/resources/webhook#execute-slackcompatible-webhook
|
||||||
|
@ -293,8 +295,7 @@ $ htpasswd -B -c .htpasswd api
|
||||||
```
|
```
|
||||||
This command will ask for a password and store it in the htpawsswd file.
|
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:
|
But you can override this behavior by specifying the location of the file:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|
|
@ -11,8 +11,8 @@ import (
|
||||||
"github.com/ncarlier/webhookd/pkg/strcase"
|
"github.com/ncarlier/webhookd/pkg/strcase"
|
||||||
)
|
)
|
||||||
|
|
||||||
// QueryParamsToShellVars convert URL query parameters to shell vars.
|
// URLValuesToShellVars convert URL values to shell vars.
|
||||||
func QueryParamsToShellVars(q url.Values) []string {
|
func URLValuesToShellVars(q url.Values) []string {
|
||||||
var params []string
|
var params []string
|
||||||
for k, v := range q {
|
for k, v := range q {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"mime"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -51,7 +52,7 @@ func triggerWebhook(w http.ResponseWriter, r *http.Request) {
|
||||||
// Check that streaming is supported
|
// Check that streaming is supported
|
||||||
flusher, ok := w.(http.Flusher)
|
flusher, ok := w.(http.Flusher)
|
||||||
if !ok {
|
if !ok {
|
||||||
http.Error(w, "Streaming not supported!", http.StatusInternalServerError)
|
http.Error(w, "streaming not supported", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,14 +69,28 @@ func triggerWebhook(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(r.Body)
|
if err = r.ParseForm(); err != nil {
|
||||||
if err != nil {
|
logger.Error.Printf("error reading from-data: %v", err)
|
||||||
logger.Error.Printf("error reading body: %v", err)
|
http.Error(w, "unable to parse request form", http.StatusBadRequest)
|
||||||
http.Error(w, "can't read body", http.StatusBadRequest)
|
|
||||||
return
|
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)...)
|
params = append(params, HTTPHeadersToShellVars(r.Header)...)
|
||||||
|
|
||||||
// logger.Debug.Printf("API REQUEST: \"%s\" with params %s...\n", p, params)
|
// logger.Debug.Printf("API REQUEST: \"%s\" with params %s...\n", p, params)
|
||||||
|
|
|
@ -14,7 +14,7 @@ func TestQueryParamsToShellVars(t *testing.T) {
|
||||||
"string": []string{"foo"},
|
"string": []string{"foo"},
|
||||||
"list": []string{"foo", "bar"},
|
"list": []string{"foo", "bar"},
|
||||||
}
|
}
|
||||||
values := api.QueryParamsToShellVars(tc)
|
values := api.URLValuesToShellVars(tc)
|
||||||
assert.ContainsStr(t, "string=foo", values, "")
|
assert.ContainsStr(t, "string=foo", values, "")
|
||||||
assert.ContainsStr(t, "list=foo,bar", values, "")
|
assert.ContainsStr(t, "list=foo,bar", values, "")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user