feat: support native streaming responses
This commit is contained in:
@@ -225,6 +225,60 @@ func TestServerPipelinedRequestsAndLargeBody(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestServerFlushesChunkedResponses(t *testing.T) {
|
||||
flushed := make(chan struct{})
|
||||
release := make(chan struct{})
|
||||
application := omni.NewWithRouter(netrouter.New())
|
||||
application.GET("/stream", func(ctx *omni.Context) error {
|
||||
flusher, ok := ctx.Raw().(http.Flusher)
|
||||
if !ok {
|
||||
return fmt.Errorf("native response writer does not implement http.Flusher")
|
||||
}
|
||||
ctx.Raw().Header().Set("Content-Type", "text/plain")
|
||||
_, _ = io.WriteString(ctx.Raw(), "one\n")
|
||||
flusher.Flush()
|
||||
close(flushed)
|
||||
<-release
|
||||
_, _ = io.WriteString(ctx.Raw(), "two\n")
|
||||
return nil
|
||||
})
|
||||
server, listener, done := startServer(t, application)
|
||||
defer stopServer(t, server, listener, done)
|
||||
|
||||
conn, err := net.Dial("tcp", listener.Addr().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer conn.Close()
|
||||
reader := bufio.NewReader(conn)
|
||||
_, _ = io.WriteString(conn, "GET /stream HTTP/1.1\r\nHost: test\r\nConnection: close\r\n\r\n")
|
||||
response, err := http.ReadResponse(reader, &http.Request{Method: http.MethodGet})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if response.StatusCode != http.StatusOK || response.TransferEncoding == nil || response.TransferEncoding[0] != "chunked" {
|
||||
response.Body.Close()
|
||||
t.Fatalf("expected chunked response, status=%d transfer=%v", response.StatusCode, response.TransferEncoding)
|
||||
}
|
||||
select {
|
||||
case <-flushed:
|
||||
case <-time.After(time.Second):
|
||||
response.Body.Close()
|
||||
t.Fatal("handler did not flush response")
|
||||
}
|
||||
first := make([]byte, len("one\n"))
|
||||
if _, err := io.ReadFull(response.Body, first); err != nil || string(first) != "one\n" {
|
||||
response.Body.Close()
|
||||
t.Fatalf("unexpected first stream chunk: %q error=%v", first, err)
|
||||
}
|
||||
close(release)
|
||||
rest, err := io.ReadAll(response.Body)
|
||||
response.Body.Close()
|
||||
if err != nil || string(rest) != "two\n" {
|
||||
t.Fatalf("unexpected remaining stream body: %q error=%v", rest, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServerProtocolBoundaries(t *testing.T) {
|
||||
application := omni.NewWithRouter(netrouter.New())
|
||||
application.GET("/health", func(ctx *omni.Context) error { return ctx.OK("ok") })
|
||||
|
||||
Reference in New Issue
Block a user