@@ -2458,6 +2458,91 @@ func TestConnReadHandlesChunkedPayload(t *testing.T) {
24582458 }
24592459}
24602460
2461+ func TestReadUsesConnWhenBufReaderNil (t * testing.T ) {
2462+ serverConn , clientConn := net .Pipe ()
2463+ t .Cleanup (func () {
2464+ if closeErr := serverConn .Close (); closeErr != nil {
2465+ t .Errorf ("failed to close server connection: %v" , closeErr )
2466+ }
2467+ })
2468+ t .Cleanup (func () {
2469+ if closeErr := clientConn .Close (); closeErr != nil {
2470+ t .Errorf ("failed to close client connection: %v" , closeErr )
2471+ }
2472+ })
2473+
2474+ proxyConn := NewConn (serverConn )
2475+ sendSecond := make (chan struct {})
2476+
2477+ go func () {
2478+ _ , _ = clientConn .Write ([]byte ("a" ))
2479+ <- sendSecond
2480+ _ , _ = clientConn .Write ([]byte ("b" ))
2481+ _ = clientConn .Close ()
2482+ }()
2483+
2484+ buf := make ([]byte , 1 )
2485+ // First read processes header detection and drains the buffer.
2486+ if _ , err := proxyConn .Read (buf ); err != nil {
2487+ t .Fatalf ("first read failed: %v" , err )
2488+ }
2489+ if proxyConn .bufReader != nil {
2490+ t .Fatalf ("expected bufReader to be nil after draining buffer" )
2491+ }
2492+
2493+ // With bufReader cleared, Read should use the underlying conn.
2494+ close (sendSecond )
2495+ if _ , err := proxyConn .Read (buf ); err != nil {
2496+ t .Fatalf ("second read failed: %v" , err )
2497+ }
2498+ if string (buf ) != "b" {
2499+ t .Fatalf ("unexpected second read payload: %q" , string (buf ))
2500+ }
2501+ }
2502+
2503+ func TestWriteToUsesConnWhenBufReaderNil (t * testing.T ) {
2504+ serverConn , clientConn := net .Pipe ()
2505+ t .Cleanup (func () {
2506+ if closeErr := serverConn .Close (); closeErr != nil {
2507+ t .Errorf ("failed to close server connection: %v" , closeErr )
2508+ }
2509+ })
2510+ t .Cleanup (func () {
2511+ if closeErr := clientConn .Close (); closeErr != nil {
2512+ t .Errorf ("failed to close client connection: %v" , closeErr )
2513+ }
2514+ })
2515+
2516+ proxyConn := NewConn (serverConn )
2517+ sendPayload := make (chan struct {})
2518+
2519+ go func () {
2520+ _ , _ = clientConn .Write ([]byte ("x" ))
2521+ <- sendPayload
2522+ _ , _ = clientConn .Write ([]byte ("payload" ))
2523+ _ = clientConn .Close ()
2524+ }()
2525+
2526+ // Process header detection and drain the buffer.
2527+ buf := make ([]byte , 1 )
2528+ if _ , err := proxyConn .Read (buf ); err != nil {
2529+ t .Fatalf ("initial read failed: %v" , err )
2530+ }
2531+ if proxyConn .bufReader != nil {
2532+ t .Fatalf ("expected bufReader to be nil after draining buffer" )
2533+ }
2534+
2535+ // With bufReader cleared, WriteTo should copy directly from conn.
2536+ close (sendPayload )
2537+ var out bytes.Buffer
2538+ if _ , err := proxyConn .WriteTo (& out ); err != nil {
2539+ t .Fatalf ("WriteTo failed: %v" , err )
2540+ }
2541+ if out .String () != "payload" {
2542+ t .Fatalf ("unexpected WriteTo output: %q" , out .String ())
2543+ }
2544+ }
2545+
24612546func benchmarkTCPProxy (size int , b * testing.B ) {
24622547 // create and start the echo backend
24632548 backend , err := net .Listen ("tcp" , testLocalhostRandomPort )
0 commit comments