@@ -390,11 +390,11 @@ func (cw *chunkWriter) Write(p []byte) (n int, err error) {
390
390
return
391
391
}
392
392
393
- func (cw * chunkWriter ) flush () {
393
+ func (cw * chunkWriter ) flush () error {
394
394
if ! cw .wroteHeader {
395
395
cw .writeHeader (nil )
396
396
}
397
- cw .res .conn .bufw .Flush ()
397
+ return cw .res .conn .bufw .Flush ()
398
398
}
399
399
400
400
func (cw * chunkWriter ) close () {
@@ -438,6 +438,9 @@ type response struct {
438
438
w * bufio.Writer // buffers output in chunks to chunkWriter
439
439
cw chunkWriter
440
440
441
+ writeTimeoutTimer * time.Timer // triggers on write timeout
442
+ writeDeadline bool // request writes timed out
443
+
441
444
// handlerHeader is the Header that Handlers get access to,
442
445
// which may be retained and mutated even after WriteHeader.
443
446
// handlerHeader is copied into cw.header at WriteHeader
@@ -1052,6 +1055,9 @@ func (c *conn) readRequest(ctx context.Context) (w *response, err error) {
1052
1055
if isH2Upgrade {
1053
1056
w .closeAfterReply = true
1054
1057
}
1058
+ if d := c .server .WriteTimeout ; d > 0 {
1059
+ w .setWriteTimeout (d )
1060
+ }
1055
1061
w .cw .res = w
1056
1062
w .w = newBufioWriterSize (& w .cw , bufferBeforeChunkingSize )
1057
1063
return w , nil
@@ -1578,6 +1584,14 @@ func (w *response) WriteString(data string) (n int, err error) {
1578
1584
return w .write (len (data ), nil , data )
1579
1585
}
1580
1586
1587
+ // setWriteTimeout lets the response know if the write was supposed to be
1588
+ // timed out, timed out requests will force be flushed on every write
1589
+ func (w * response ) setWriteTimeout (d time.Duration ) {
1590
+ w .writeTimeoutTimer = time .AfterFunc (d , func () {
1591
+ w .writeDeadline = true
1592
+ })
1593
+ }
1594
+
1581
1595
// either dataB or dataS is non-zero.
1582
1596
func (w * response ) write (lenData int , dataB []byte , dataS string ) (n int , err error ) {
1583
1597
if w .conn .hijacked () {
@@ -1613,10 +1627,16 @@ func (w *response) write(lenData int, dataB []byte, dataS string) (n int, err er
1613
1627
return 0 , ErrContentLength
1614
1628
}
1615
1629
if dataB != nil {
1616
- return w .w .Write (dataB )
1630
+ n , err = w .w .Write (dataB )
1617
1631
} else {
1618
- return w .w .WriteString (dataS )
1632
+ n , err = w .w .WriteString (dataS )
1633
+ }
1634
+ if err == nil && w .writeDeadline {
1635
+ // r.Flush returns no errors, flush manually
1636
+ w .w .Flush ()
1637
+ err = w .cw .flush ()
1619
1638
}
1639
+ return
1620
1640
}
1621
1641
1622
1642
func (w * response ) finishRequest () {
@@ -1631,6 +1651,9 @@ func (w *response) finishRequest() {
1631
1651
w .cw .close ()
1632
1652
w .conn .bufw .Flush ()
1633
1653
1654
+ if w .writeTimeoutTimer != nil {
1655
+ w .writeTimeoutTimer .Stop ()
1656
+ }
1634
1657
w .conn .r .abortPendingRead ()
1635
1658
1636
1659
// Close the body (regardless of w.closeAfterReply) so we can
0 commit comments