@@ -424,6 +424,16 @@ type response struct {
424
424
wants10KeepAlive bool // HTTP/1.0 w/ Connection "keep-alive"
425
425
wantsClose bool // HTTP request has Connection "close"
426
426
427
+ // canWriteContinue is a boolean value accessed as an atomic int32
428
+ // that says whether or not a 100 Continue header can be written
429
+ // to the connection.
430
+ // writeContinueMu must be held while writing the header.
431
+ // These two fields together synchronize the body reader
432
+ // (the expectContinueReader, which wants to write 100 Continue)
433
+ // against the main writer.
434
+ canWriteContinue atomicBool
435
+ writeContinueMu sync.Mutex
436
+
427
437
w * bufio.Writer // buffers output in chunks to chunkWriter
428
438
cw chunkWriter
429
439
@@ -514,6 +524,7 @@ type atomicBool int32
514
524
515
525
func (b * atomicBool ) isSet () bool { return atomic .LoadInt32 ((* int32 )(b )) != 0 }
516
526
func (b * atomicBool ) setTrue () { atomic .StoreInt32 ((* int32 )(b ), 1 ) }
527
+ func (b * atomicBool ) setFalse () { atomic .StoreInt32 ((* int32 )(b ), 0 ) }
517
528
518
529
// declareTrailer is called for each Trailer header when the
519
530
// response header is written. It notes that a header will need to be
@@ -876,21 +887,27 @@ type expectContinueReader struct {
876
887
resp * response
877
888
readCloser io.ReadCloser
878
889
closed bool
879
- sawEOF bool
890
+ sawEOF atomicBool
880
891
}
881
892
882
893
func (ecr * expectContinueReader ) Read (p []byte ) (n int , err error ) {
883
894
if ecr .closed {
884
895
return 0 , ErrBodyReadAfterClose
885
896
}
886
- if ! ecr .resp .wroteContinue && ! ecr .resp .conn .hijacked () {
887
- ecr .resp .wroteContinue = true
888
- ecr .resp .conn .bufw .WriteString ("HTTP/1.1 100 Continue\r \n \r \n " )
889
- ecr .resp .conn .bufw .Flush ()
897
+ w := ecr .resp
898
+ if ! w .wroteContinue && w .canWriteContinue .isSet () && ! w .conn .hijacked () {
899
+ w .wroteContinue = true
900
+ w .writeContinueMu .Lock ()
901
+ if w .canWriteContinue .isSet () {
902
+ w .conn .bufw .WriteString ("HTTP/1.1 100 Continue\r \n \r \n " )
903
+ w .conn .bufw .Flush ()
904
+ w .canWriteContinue .setFalse ()
905
+ }
906
+ w .writeContinueMu .Unlock ()
890
907
}
891
908
n , err = ecr .readCloser .Read (p )
892
909
if err == io .EOF {
893
- ecr .sawEOF = true
910
+ ecr .sawEOF . setTrue ()
894
911
}
895
912
return
896
913
}
@@ -1309,7 +1326,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
1309
1326
// because we don't know if the next bytes on the wire will be
1310
1327
// the body-following-the-timer or the subsequent request.
1311
1328
// See Issue 11549.
1312
- if ecr , ok := w .req .Body .(* expectContinueReader ); ok && ! ecr .sawEOF {
1329
+ if ecr , ok := w .req .Body .(* expectContinueReader ); ok && ! ecr .sawEOF . isSet () {
1313
1330
w .closeAfterReply = true
1314
1331
}
1315
1332
@@ -1554,6 +1571,17 @@ func (w *response) write(lenData int, dataB []byte, dataS string) (n int, err er
1554
1571
}
1555
1572
return 0 , ErrHijacked
1556
1573
}
1574
+
1575
+ if w .canWriteContinue .isSet () {
1576
+ // Body reader wants to write 100 Continue but hasn't yet.
1577
+ // Tell it not to. The store must be done while holding the lock
1578
+ // because the lock makes sure that there is not an active write
1579
+ // this very moment.
1580
+ w .writeContinueMu .Lock ()
1581
+ w .canWriteContinue .setFalse ()
1582
+ w .writeContinueMu .Unlock ()
1583
+ }
1584
+
1557
1585
if ! w .wroteHeader {
1558
1586
w .WriteHeader (StatusOK )
1559
1587
}
@@ -1866,6 +1894,7 @@ func (c *conn) serve(ctx context.Context) {
1866
1894
if req .ProtoAtLeast (1 , 1 ) && req .ContentLength != 0 {
1867
1895
// Wrap the Body reader with one that replies on the connection
1868
1896
req .Body = & expectContinueReader {readCloser : req .Body , resp : w }
1897
+ w .canWriteContinue .setTrue ()
1869
1898
}
1870
1899
} else if req .Header .get ("Expect" ) != "" {
1871
1900
w .sendExpectationFailed ()
0 commit comments