feat(): improve control on streaming protocol

close #51
This commit is contained in:
Nicolas Carlier 2022-02-05 08:55:09 +01:00
parent bf6fe82b54
commit 4e6298dda7
3 changed files with 52 additions and 8 deletions

View File

@ -91,11 +91,15 @@ The directory structure define the webhook URL.
You can omit the script extension. If you do, webhookd will search for a `.sh` file. You can omit the script extension. If you do, webhookd will search for a `.sh` file.
If the script exists, the output the will be streamed to the HTTP response. If the script exists, the output the will be streamed to the HTTP response.
The streaming technology depends on the HTTP method used. The streaming technology depends on the HTTP request:
With `POST` the response will be chunked.
With `GET` the response will use [Server-sent events][sse]. - [Server-sent events][sse] is used when:
- Using `GET` verb
- Using `text/event-stream` in `Accept` request header
- [Chunked Transfer Coding][chunked] is used otherwise.
[sse]: https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events [sse]: https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events
[chunked]: https://datatracker.ietf.org/doc/html/rfc2616#section-3.6.1
*Example:* *Example:*
@ -108,7 +112,7 @@ echo "foo foo foo"
echo "bar bar bar" echo "bar bar bar"
``` ```
Output using `POST` (`Chunked transfer encoding`): Output using `POST` or `GET` (`Chunked Transfer Coding`):
```bash ```bash
$ curl -v -XPOST http://localhost:8080/foo/bar $ curl -v -XPOST http://localhost:8080/foo/bar
@ -120,10 +124,10 @@ foo foo foo
bar bar bar bar bar bar
``` ```
Output using `GET` (`Server-sent events`): Output using `GET` and `Accept` header (`Server-sent events`):
```bash ```bash
$ curl -v -XGET http://localhost:8080/foo/bar $ curl -v --header "Accept: text/event-stream" -XGET http://localhost:8080/foo/bar
< HTTP/1.1 200 OK < HTTP/1.1 200 OK
< Content-Type: text/event-stream < Content-Type: text/event-stream
< Transfer-Encoding: chunked < Transfer-Encoding: chunked

View File

@ -87,7 +87,9 @@ func triggerWebhook(w http.ResponseWriter, r *http.Request) {
// Put work in queue // Put work in queue
worker.WorkQueue <- *work worker.WorkQueue <- *work
if r.Method == "GET" { // Use content negotiation to enable Server-Sent Events
useSSE := r.Method == "GET" && r.Header.Get("Accept") == "text/event-stream"
if useSSE {
// Send SSE response // Send SSE response
w.Header().Set("Content-Type", "text/event-stream") w.Header().Set("Content-Type", "text/event-stream")
} else { } else {
@ -105,7 +107,7 @@ func triggerWebhook(w http.ResponseWriter, r *http.Request) {
break break
} }
if r.Method == "GET" { if useSSE {
fmt.Fprintf(w, "data: %s\n\n", msg) // Send SSE response fmt.Fprintf(w, "data: %s\n\n", msg) // Send SSE response
} else { } else {
fmt.Fprintf(w, "%s\n", msg) // Send chunked response fmt.Fprintf(w, "%s\n", msg) // Send chunked response

38
tooling/html/console.html Normal file
View File

@ -0,0 +1,38 @@
<!DOCTYPE html>
<html>
<head>
<title>Basic Webhookd UI</title>
<meta charset="UTF-8">
</head>
<body>
<form onsubmit="return sendRequest(this)">
<input name="action" type="text" value="echo" required />
<button type="submit">GET</button>
</form>
<pre id="result">
<!--Server response will be inserted here-->
</pre>
<script>
/**
* @param {HTMLFormElement} form - Form with action.
*/
function sendRequest(form) {
const action = form.elements.namedItem("action").value;
const source = new EventSource(`http://localhost:8080/${action}`);
source.onopen = () => {
console.log('connected');
};
source.onmessage = (event) => {
console.log(event.data);
document.getElementById("result").innerHTML += event.data + "<br>";
};
source.onerror = event => {
console.log(event);
source.close()
};
return false;
}
</script>
</body>
</html>