nbio: Cant send large response.

Hello. I try to replace net/http in gin framework by your example. But when I replace I have error in this part, about CloseNotifier interface. `

                c.Stream(func(w io.Writer) bool {
		n, err := data.Read(vbuf)
		if err != nil && err != io.EOF {
			fmt.Println("read error", err)
			return false
		}
		if n > 0 {
			if _, err := w.Write(vbuf[:n]); err == nil {
				return true
			}
		}
		return false)

`

When I try to write data without check conn state like io.Copy(c.Writer,dataReader) but get error invalid write result in case if data size reach around 500kb. When I try to write by one part c.Writer.Write(io.ReadAll(dataReader) limit increase to 4mb.

Versions: github.com/gin-gonic/gin v1.8.2 github.com/lesismal/nbio v1.3.9

Sorry, my bad english.

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Comments: 20 (12 by maintainers)

Commits related to this issue

Most upvoted comments

labstack/echo has the same problem, but its ResponseWriter field is exported, record here:

func onHello(c echo.Context) error {
	w := c.Response().Writer.(*nbhttp.Response)
	http.ServeFile(w, c.Request(), `./test.txt`)
	return nil
}

Yes its working. Thank you.

My previous type conversion was wrong, we can hack like this, then it works:

func nbhttpResponse(c *gin.Context) *nbhttp.Response {
	type GinContext struct {
		Writer struct {
			http.ResponseWriter
		}
	}
	return (*(**GinContext)(unsafe.Pointer(&c))).Writer.ResponseWriter.(*nbhttp.Response)
}

func onHello(c *gin.Context) {
	// if you have write status code using c, should call WriteHeaderNow() before using nbhttp.Response
	// c.Writer.WriteHeaderNow()

	w := nbhttpResponse(c)
	http.ServeFile(w, c.Request, `./test.txt`)
}

It depends on gin.Context’s struct layout.

Yes it is. Thank you.

nbhttp.Response implements io.ReaderFrom, if use std http servefile, it will call sendfile. But when I try gin, it doesn’t call sendfile, I take a look at the code of gin, gin.Context.Writer’s assertion to io.ReaderFrom failed, so if we use c.ServeFile or io.Copy we failed. To use sendfile, we need to convert the type ourself like this:

func onHello(c *gin.Context) {
	f, err := os.Open(`./test.txt`)
	if err != nil {
		panic(err)
	}
	res := *(**nbhttp.Response)(unsafe.Pointer(&c.Writer))
	io.Copy(res, f)
}