I am trying to use gin to construct a stream server supporting http-flv. As expected, if the header "Content-Length" is not set, the connection will be kept open. However, whenever I invoke the method context.Writer.Write([]byte), I get the error mentioned above. I refered to the comment attached in file server.go, which claims "Additionally, if the total size of all written data is under a few KB and there are no Flush calls, the Content-Length header is added automatically." func NewFlvWriter(ctx gin.Context, parent flvMuxer) (*FlvWriter, error) { // TODO: 填充某些字段 writer := &FlvWriter{ remoteAddr: ctx.RemoteIP(), streamName: parent.pathName, buf: make([]byte, 11), parent: parent, ctx: ctx, }

chPacketFlvWriter := make(chan *flvPacket, 64)
ctx.Header("Transfer-Encoding", "chunked")
ctx.Header("Content-Type", "application/octet-stream")
//ctx.Header("Content-Length", "-1")
ctx.Writer.WriteHeader(200)

_, err := ctx.Writer.Write(flvHeader)
if err != nil {
    writer.Log(logger.Error, "error writing flv header: "+err.Error()+", content length: "+ctx.Writer.Header().Get("Content-Length"))
    return nil, err
}
pio.PutI32BE(writer.buf[:4], 0)
_, err = ctx.Writer.Write(writer.buf[:4])
if err != nil {
    writer.Log(logger.Error, "error writing blanks: "+err.Error())
    return nil, err
}

// TODO: 记得在Writer结束之前销毁里面的对应的kv
parent.packetBuffer.Store(ctx, chPacketFlvWriter)
return writer, nil

}

Comment From: kaylee595

I can't reproduce your problem, you can try to set a breakpoint at line 1177 of server.go to try to see the value of v/cl. Please set a breakpoint at w.contentLength = v below for debugging

// server.go

func (w *response) WriteHeader(code int) {
    if w.conn.hijacked() {
        caller := relevantCaller()
        w.conn.server.logf("http: response.WriteHeader on hijacked connection from %s (%s:%d)", caller.Function, path.Base(caller.File), caller.Line)
        return
    }
    if w.wroteHeader {
        caller := relevantCaller()
        w.conn.server.logf("http: superfluous response.WriteHeader call from %s (%s:%d)", caller.Function, path.Base(caller.File), caller.Line)
        return
    }
    checkWriteHeaderCode(code)

    // Handle informational headers
    if code >= 100 && code <= 199 {
        // Prevent a potential race with an automatically-sent 100 Continue triggered by Request.Body.Read()
        if code == 100 && w.canWriteContinue.Load() {
            w.writeContinueMu.Lock()
            w.canWriteContinue.Store(false)
            w.writeContinueMu.Unlock()
        }

        writeStatusLine(w.conn.bufw, w.req.ProtoAtLeast(1, 1), code, w.statusBuf[:])

        // Per RFC 8297 we must not clear the current header map
        w.handlerHeader.WriteSubset(w.conn.bufw, excludedHeadersNoBody)
        w.conn.bufw.Write(crlf)
        w.conn.bufw.Flush()

        return
    }

    w.wroteHeader = true
    w.status = code

    if w.calledHeader && w.cw.header == nil {
        w.cw.header = w.handlerHeader.Clone()
    }

    if cl := w.handlerHeader.get("Content-Length"); cl != "" {
        v, err := strconv.ParseInt(cl, 10, 64)
        if err == nil && v >= 0 {
            w.contentLength = v
        } else {
            w.conn.server.logf("http: invalid Content-Length of %q", cl)
            w.handlerHeader.Del("Content-Length")
        }
    }
}