feat: stream native request bodies

This commit is contained in:
2026-09-22 09:57:09 +08:00
parent c5e415ca52
commit 5ab906098f
5 changed files with 288 additions and 86 deletions

View File

@@ -107,6 +107,47 @@ func TestServerRejectsMalformedBodyAndLimits(t *testing.T) {
}
}
func TestServerStreamsContentLengthBodyToHandler(t *testing.T) {
entered := make(chan struct{})
application := omni.NewWithRouter(netrouter.New())
application.POST("/body", func(ctx *omni.Context) error {
close(entered)
body, err := io.ReadAll(ctx.Request().Body)
if err != nil {
return err
}
return ctx.OK(map[string]string{"body": string(body)})
})
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()
if _, err := io.WriteString(conn, "POST /body HTTP/1.1\r\nHost: test\r\nContent-Length: 5\r\n\r\nhel"); err != nil {
t.Fatal(err)
}
select {
case <-entered:
case <-time.After(time.Second):
t.Fatal("handler did not start before the complete body arrived")
}
if _, err := io.WriteString(conn, "lo"); err != nil {
t.Fatal(err)
}
response, err := http.ReadResponse(bufio.NewReader(conn), &http.Request{Method: http.MethodPost})
if err != nil {
t.Fatal(err)
}
body, err := io.ReadAll(response.Body)
response.Body.Close()
if err != nil || response.StatusCode != http.StatusOK || !strings.Contains(string(body), `"body":"hello"`) {
t.Fatalf("unexpected streamed body response: status=%d body=%s error=%v", response.StatusCode, body, err)
}
}
func TestServerChunkedBodyAndTrailers(t *testing.T) {
application := omni.NewWithRouter(netrouter.New())
application.POST("/body", func(ctx *omni.Context) error {
@@ -154,11 +195,18 @@ func TestServerChunkedBodyLimit(t *testing.T) {
}
}
func TestServerSlowBodyTimesOutBeforeHandler(t *testing.T) {
func TestServerSlowBodyTimesOutWithoutSuccessfulHandler(t *testing.T) {
var handlerCalls atomic.Int32
application := omni.NewWithRouter(netrouter.New())
application.POST("/body", func(ctx *omni.Context) error {
body, err := io.ReadAll(ctx.Request().Body)
if err != nil {
return err
}
handlerCalls.Add(1)
if len(body) != 4 {
return fmt.Errorf("unexpected body length %d", len(body))
}
return ctx.OK("ok")
})
server := native.New(application)
@@ -178,14 +226,10 @@ func TestServerSlowBodyTimesOutBeforeHandler(t *testing.T) {
t.Fatal(err)
}
defer conn.Close()
conn.SetReadDeadline(time.Now().Add(time.Second))
_, _ = io.WriteString(conn, "POST /body HTTP/1.1\r\nHost: test\r\nContent-Length: 4\r\n\r\na")
buffer := make([]byte, 1)
if _, err := conn.Read(buffer); err == nil {
t.Fatal("expected slow request body to time out and close")
}
requirePeerClose(t, conn)
if handlerCalls.Load() != 0 {
t.Fatal("handler ran before the request body was complete")
t.Fatal("handler reported success before the request body was complete")
}
}