@@ -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
@@ -877,21 +888,27 @@ type expectContinueReader struct {
877
888
resp * response
878
889
readCloser io.ReadCloser
879
890
closed bool
880
- sawEOF bool
891
+ sawEOF atomicBool
881
892
}
882
893
883
894
func (ecr * expectContinueReader ) Read (p []byte ) (n int , err error ) {
884
895
if ecr .closed {
885
896
return 0 , ErrBodyReadAfterClose
886
897
}
887
- if ! ecr .resp .wroteContinue && ! ecr .resp .conn .hijacked () {
888
- ecr .resp .wroteContinue = true
889
- ecr .resp .conn .bufw .WriteString ("HTTP/1.1 100 Continue\r \n \r \n " )
890
- ecr .resp .conn .bufw .Flush ()
898
+ w := ecr .resp
899
+ if ! w .wroteContinue && w .canWriteContinue .isSet () && ! w .conn .hijacked () {
900
+ w .wroteContinue = true
901
+ w .writeContinueMu .Lock ()
902
+ if w .canWriteContinue .isSet () {
903
+ w .conn .bufw .WriteString ("HTTP/1.1 100 Continue\r \n \r \n " )
904
+ w .conn .bufw .Flush ()
905
+ w .canWriteContinue .setFalse ()
906
+ }
907
+ w .writeContinueMu .Unlock ()
891
908
}
892
909
n , err = ecr .readCloser .Read (p )
893
910
if err == io .EOF {
894
- ecr .sawEOF = true
911
+ ecr .sawEOF . setTrue ()
895
912
}
896
913
return
897
914
}
@@ -1310,7 +1327,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
1310
1327
// because we don't know if the next bytes on the wire will be
1311
1328
// the body-following-the-timer or the subsequent request.
1312
1329
// See Issue 11549.
1313
- if ecr , ok := w .req .Body .(* expectContinueReader ); ok && ! ecr .sawEOF {
1330
+ if ecr , ok := w .req .Body .(* expectContinueReader ); ok && ! ecr .sawEOF . isSet () {
1314
1331
w .closeAfterReply = true
1315
1332
}
1316
1333
@@ -1560,6 +1577,17 @@ func (w *response) write(lenData int, dataB []byte, dataS string) (n int, err er
1560
1577
}
1561
1578
return 0 , ErrHijacked
1562
1579
}
1580
+
1581
+ if w .canWriteContinue .isSet () {
1582
+ // Body reader wants to write 100 Continue but hasn't yet.
1583
+ // Tell it not to. The store must be done while holding the lock
1584
+ // because the lock makes sure that there is not an active write
1585
+ // this very moment.
1586
+ w .writeContinueMu .Lock ()
1587
+ w .canWriteContinue .setFalse ()
1588
+ w .writeContinueMu .Unlock ()
1589
+ }
1590
+
1563
1591
if ! w .wroteHeader {
1564
1592
w .WriteHeader (StatusOK )
1565
1593
}
@@ -1871,6 +1899,7 @@ func (c *conn) serve(ctx context.Context) {
1871
1899
if req .ProtoAtLeast (1 , 1 ) && req .ContentLength != 0 {
1872
1900
// Wrap the Body reader with one that replies on the connection
1873
1901
req .Body = & expectContinueReader {readCloser : req .Body , resp : w }
1902
+ w .canWriteContinue .setTrue ()
1874
1903
}
1875
1904
} else if req .Header .get ("Expect" ) != "" {
1876
1905
w .sendExpectationFailed ()
0 commit comments