valyala / fasthttp

Fast HTTP package for Go. Tuned for high performance. Zero memory allocations in hot paths. Up to 10x faster than net/http
MIT License
21.94k stars 1.76k forks source link

SetBodyStreamWriter doesn't set EOF #1591

Open burgesQ opened 1 year ago

burgesQ commented 1 year ago

I'm trying to "live stream" the content of file that I'm live generating form within the server.

When running the following code, the client would hang indefinitely once all the data chunks read, as if the Read method never returned EOF ?

Maybe I'm missing something ? thanks for any help 🙏🏻

Currently, the server approach looks like (simplified for reproducibility):

ctx.Response.SetBodyStreamWriter(func(w *bufio.Writer) {
                defer w.Flush()

                for i := 0; i < 10; i++ {
                    _, err := w.Write([]byte(fmt.Sprintf("chunk %d\n", i)))
                    if err != nil {
                         // handling error
                        return
                    }

                    w.Flush()
                }
            })

And the client read the body with a simple:

    buf := make([]byte, 1)
    for {
        _, err := resp.Body.Read(buf)
        if err != nil {
            if err != io.EOF {
                fmt.Println("failed to read response body:", err)
            }

            break
        }

        fmt.Print(string(buf[0]))
    }
erikdubbelboer commented 1 year ago

Do you have a standalone reproducible example?

For example the following code works fine:

package main

import (
    "bufio"
    "fmt"

    "github.com/valyala/fasthttp"
)

func handler(ctx *fasthttp.RequestCtx) {
    ctx.Response.SetBodyStreamWriter(func(w *bufio.Writer) {
        defer w.Flush()

        for i := 0; i < 10; i++ {
            _, err := w.Write([]byte(fmt.Sprintf("chunk %d\n", i)))
            if err != nil {
                // handling error
                return
            }

            w.Flush()
        }
    })
}

func main() {
    if err := fasthttp.ListenAndServe(":8080", handler); err != nil {
        panic(err)
    }
}
% curl localhost:8080 -v
*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.88.1
> Accept: */*
> 
< HTTP/1.1 200 OK
< Server: fasthttp
< Date: Sat, 08 Jul 2023 07:49:17 GMT
< Content-Type: text/plain; charset=utf-8
< Transfer-Encoding: chunked
< 
chunk 0
chunk 1
chunk 2
chunk 3
chunk 4
chunk 5
chunk 6
chunk 7
chunk 8
chunk 9
* Connection #0 to host localhost left intact