@@ -649,18 +649,22 @@ func TestReverseProxy_CopyBuffer(t *testing.T) {
649
649
var proxyLog bytes.Buffer
650
650
rproxy := NewSingleHostReverseProxy (rpURL )
651
651
rproxy .ErrorLog = log .New (& proxyLog , "" , log .Lshortfile )
652
- frontendProxy := httptest .NewServer (rproxy )
652
+ donec := make (chan bool , 1 )
653
+ frontendProxy := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
654
+ defer func () { donec <- true }()
655
+ rproxy .ServeHTTP (w , r )
656
+ }))
653
657
defer frontendProxy .Close ()
654
658
655
- resp , err := http .Get (frontendProxy .URL )
656
- if err != nil {
657
- t .Fatalf ("failed to reach proxy: %v" , err )
658
- }
659
- defer resp .Body .Close ()
660
-
661
- if _ , err := ioutil .ReadAll (resp .Body ); err == nil {
659
+ if _ , err = frontendProxy .Client ().Get (frontendProxy .URL ); err == nil {
662
660
t .Fatalf ("want non-nil error" )
663
661
}
662
+ // The race detector complains about the proxyLog usage in logf in copyBuffer
663
+ // and our usage below with proxyLog.Bytes() so we're explicitly using a
664
+ // channel to ensure that the ReverseProxy's ServeHTTP is done before we
665
+ // continue after Get.
666
+ <- donec
667
+
664
668
expected := []string {
665
669
"EOF" ,
666
670
"read" ,
@@ -813,3 +817,35 @@ func (cc *checkCloser) Close() error {
813
817
func (cc * checkCloser ) Read (b []byte ) (int , error ) {
814
818
return len (b ), nil
815
819
}
820
+
821
+ // Issue 23643: panic on body copy error
822
+ func TestReverseProxy_PanicBodyError (t * testing.T ) {
823
+ backendServer := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
824
+ out := "this call was relayed by the reverse proxy"
825
+ // Coerce a wrong content length to induce io.ErrUnexpectedEOF
826
+ w .Header ().Set ("Content-Length" , fmt .Sprintf ("%d" , len (out )* 2 ))
827
+ fmt .Fprintln (w , out )
828
+ }))
829
+ defer backendServer .Close ()
830
+
831
+ rpURL , err := url .Parse (backendServer .URL )
832
+ if err != nil {
833
+ t .Fatal (err )
834
+ }
835
+
836
+ rproxy := NewSingleHostReverseProxy (rpURL )
837
+
838
+ // Ensure that the handler panics when the body read encounters an
839
+ // io.ErrUnexpectedEOF
840
+ defer func () {
841
+ err := recover ()
842
+ if err == nil {
843
+ t .Fatal ("handler should have panicked" )
844
+ }
845
+ if err != http .ErrAbortHandler {
846
+ t .Fatal ("expected ErrAbortHandler, got" , err )
847
+ }
848
+ }()
849
+ req , _ := http .NewRequest ("GET" , "http://foo.tld/" , nil )
850
+ rproxy .ServeHTTP (httptest .NewRecorder (), req )
851
+ }
0 commit comments