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