Skip to content

Commit

Permalink
Add /sse endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
sharat87 committed Nov 21, 2024
1 parent 1312f04 commit 39993df
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 10 deletions.
2 changes: 1 addition & 1 deletion api-tests/drip_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ func TestDrip(t *testing.T) {
Path: "drip?duration=1&delay=0",
})
s.Equal(http.StatusOK, resp.StatusCode)
s.Equal(c.TextEventStream, resp.Header.Get(c.ContentType))
s.Equal("text/octet-stream", resp.Header.Get(c.ContentType))
s.Equal(strings.Repeat("*", 10), body)
}
2 changes: 1 addition & 1 deletion assets/_foot.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<footer>
<p>A project by <a href='https://sharats.me' target=_blank rel=noopener>Shri</a>.
{{- if .commitShort}}
Built from <a href="https://github.com/sharat87/httpbun/tree/{{.commit}}">{{.commitShort}}</a> on {{.date}}.
Built from <a href="https://github.com/sharat87/httpbun/tree/{{.commit}}">{{.commitShort}}</a> on <code>{{.date}}</code>.
{{- end}}</p>
</footer>

Expand Down
16 changes: 11 additions & 5 deletions assets/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ <h1><img alt=Logo src='{{.pathPrefix}}/assets/icon-180.png'> Httpbun</h1>
<ol>
<li>The <code>/mix</code> endpoint, and the <a href="{{.pathPrefix}}/mixer">Mixer</a>.
<li>The <code>/run</code> endpoint, and the <a href="{{.pathPrefix}}/runner">Runner</a>.
<li>The <a href=#payload>/payload endpoint</a>
<li>Allowing request body in <a href=#get>/get</a> endpoint.
<li>The <a href=#payload>/payload endpoint</a>.
<li>Allowing request body in <a href=#get>/get endpoint</a>.
<li>Accept <em>any</em> method in <a href=#headers>/headers</a> and most other such endpoints.
<li>Not <a href="https://github.com/postmanlabs/httpbin/blob/f8ec666b4d1b654e4ff6aedd356f510dcac09f83/httpbin/helpers.py#L40">hiding some headers</a> in responses.
<li>More practical handling of unescaped special characters in <code>x-www-form-urlencoded</code> payloads.
Expand Down Expand Up @@ -200,6 +200,11 @@ <h3 id=client-tuned-responses>Client Tuned Response <a href="#client-tuned-respo
When using <code>/drip-lines</code>, a newline character is written after every piece of data.
</dd>

<dt id=sse>/sse</dt>
<dd>Responds with 10 <a href="https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events">
Server sent events</a>, each after 1s of delay. The count and delay aren't configurable today.
</dd>

<dt id=links>/links/<span class=var>{count}</span></dt>
<dt id=links-offset>/links/<span class=var>{count}</span>/<span class=var>{offset}</span></dt>
<dd>Returns an HTML document with <code>count</code> links, which in turn respond with HTML documents with links
Expand Down Expand Up @@ -307,9 +312,10 @@ <h2 id=configuration>Configuration <a href="#configuration">&para;</a></h2>
</dd>

<dt id=configuration-root-is-any>--root-is-any</dt>
<dd>If provided, all endpoint routes are disabled, and all endpoints behave like `/any`. This means that when this
option is given, all HTML pages will also become inaccessible. Like the homepage, Mixer UI, help pages etc. A
hosted instance with this option enabled is available at <a href="https://any.httpbun.com">any.httpbun.com</a>.
<dd>If provided, all endpoint routes are disabled, and all endpoints behave like <code>/any</code>. This means that
when this option is given, all HTML pages will also become inaccessible. Like the homepage, Mixer UI, help pages
etc. A hosted instance with this option enabled is available at
<a href="https://any.httpbun.com">any.httpbun.com</a>.
</dd>

</dl>
Expand Down
1 change: 0 additions & 1 deletion c/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,3 @@ const WWWAuthenticate = "WWW-Authenticate"
const ApplicationJSON = "application/json"
const TextPlain = "text/plain; charset=utf-8"
const TextHTML = "text/html; charset=utf-8"
const TextEventStream = "text/event-stream"
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/sharat87/httpbun

go 1.21
go 1.23

require (
github.com/dop251/goja v0.0.0-20241024094426-79f3a7efcdbd
Expand Down
4 changes: 3 additions & 1 deletion routes/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/sharat87/httpbun/routes/mix"
"github.com/sharat87/httpbun/routes/redirect"
"github.com/sharat87/httpbun/routes/run"
"github.com/sharat87/httpbun/routes/sse"
"github.com/sharat87/httpbun/routes/static"
"github.com/sharat87/httpbun/util"
"log"
Expand Down Expand Up @@ -73,6 +74,7 @@ func GetRoutes() []Route {
maps.Copy(allRoutes2, static.Routes)
maps.Copy(allRoutes, cookies.Routes)
maps.Copy(allRoutes2, run.Routes)
maps.Copy(allRoutes, sse.Routes)

for pat, fn := range allRoutes {
routes = append(routes, Route{
Expand Down Expand Up @@ -264,7 +266,7 @@ func handleDrip(ex *exchange.Exchange) {
}

ex.ResponseWriter.Header().Set("Cache-Control", "no-cache")
ex.ResponseWriter.Header().Set(c.ContentType, "text/event-stream")
ex.ResponseWriter.Header().Set(c.ContentType, "text/octet-stream")
ex.ResponseWriter.WriteHeader(code)

interval := time.Duration(float32(time.Second) * float32(duration) / float32(numbytes))
Expand Down
48 changes: 48 additions & 0 deletions routes/sse/handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package sse

import (
"fmt"
"github.com/sharat87/httpbun/c"
"github.com/sharat87/httpbun/exchange"
"log"
"net/http"
"strings"
"time"
)

var Routes = map[string]exchange.HandlerFn{
`/sse`: handleServerSentEvents,
}

func handleServerSentEvents(ex *exchange.Exchange) {
ex.ResponseWriter.Header().Set("Cache-Control", "no-store")
ex.ResponseWriter.Header().Set(c.ContentType, "text/event-stream")
ex.ResponseWriter.WriteHeader(http.StatusOK)

if f, ok := ex.ResponseWriter.(http.Flusher); ok {
f.Flush()
} else {
log.Println("Flush not available. Dripping and streaming not supported on this platform.")
}

for id := range 10 {
time.Sleep(1 * time.Second)
_, err := fmt.Fprint(ex.ResponseWriter, strings.Join(pingMessage(id+1), "\n")+"\n\n")
if err != nil {
return
}
if f, ok := ex.ResponseWriter.(http.Flusher); ok {
f.Flush()
} else {
log.Println("Flush not available. Dripping and streaming not supported on this platform.")
}
}
}

func pingMessage(id int) []string {
return []string{
"event: ping",
fmt.Sprintf("id: %v", id),
"data: a ping event",
}
}

0 comments on commit 39993df

Please sign in to comment.