@@ -223,6 +223,47 @@ func TestUseWithReadHeaderTimeout(t *testing.T) {
223223 }
224224}
225225
226+ func TestNewConnSetReadHeaderTimeoutOption (t * testing.T ) {
227+ conn , peer := net .Pipe ()
228+ t .Cleanup (func () {
229+ if closeErr := conn .Close (); closeErr != nil {
230+ t .Errorf ("failed to close connection: %v" , closeErr )
231+ }
232+ })
233+ t .Cleanup (func () {
234+ if closeErr := peer .Close (); closeErr != nil {
235+ t .Errorf ("failed to close peer connection: %v" , closeErr )
236+ }
237+ })
238+
239+ // Ensure SetReadHeaderTimeout sets the connection-specific timeout.
240+ timeout := 150 * time .Millisecond
241+ proxyConn := NewConn (conn , SetReadHeaderTimeout (timeout ))
242+ if proxyConn .readHeaderTimeout != timeout {
243+ t .Fatalf ("expected readHeaderTimeout %v, got %v" , timeout , proxyConn .readHeaderTimeout )
244+ }
245+ }
246+
247+ func TestNewConnSetReadHeaderTimeoutIgnoresNegative (t * testing.T ) {
248+ conn , peer := net .Pipe ()
249+ t .Cleanup (func () {
250+ if closeErr := conn .Close (); closeErr != nil {
251+ t .Errorf ("failed to close connection: %v" , closeErr )
252+ }
253+ })
254+ t .Cleanup (func () {
255+ if closeErr := peer .Close (); closeErr != nil {
256+ t .Errorf ("failed to close peer connection: %v" , closeErr )
257+ }
258+ })
259+
260+ // Negative values should be ignored, leaving the timeout unset.
261+ proxyConn := NewConn (conn , SetReadHeaderTimeout (- 1 ))
262+ if proxyConn .readHeaderTimeout != 0 {
263+ t .Fatalf ("expected readHeaderTimeout to remain 0, got %v" , proxyConn .readHeaderTimeout )
264+ }
265+ }
266+
226267func TestReadHeaderTimeoutRespectsEarlierDeadline (t * testing.T ) {
227268 const (
228269 headerTimeout = 200 * time .Millisecond
@@ -2038,6 +2079,54 @@ type testConn struct {
20382079 net.Conn // nil; crash on any unexpected use
20392080}
20402081
2082+ type deadlineConn struct {
2083+ deadline time.Time
2084+ readDeadline time.Time
2085+ writeDeadline time.Time
2086+ }
2087+
2088+ func (c * deadlineConn ) Read (_ []byte ) (int , error ) { return 0 , io .EOF }
2089+ func (c * deadlineConn ) Write (p []byte ) (int , error ) { return len (p ), nil }
2090+ func (c * deadlineConn ) Close () error { return nil }
2091+ func (c * deadlineConn ) LocalAddr () net.Addr { return dummyAddr ("local" ) }
2092+ func (c * deadlineConn ) RemoteAddr () net.Addr { return dummyAddr ("remote" ) }
2093+ func (c * deadlineConn ) SetDeadline (t time.Time ) error {
2094+ c .deadline = t
2095+ return nil
2096+ }
2097+ func (c * deadlineConn ) SetReadDeadline (t time.Time ) error {
2098+ c .readDeadline = t
2099+ return nil
2100+ }
2101+ func (c * deadlineConn ) SetWriteDeadline (t time.Time ) error {
2102+ c .writeDeadline = t
2103+ return nil
2104+ }
2105+
2106+ type noReadFromConn struct {
2107+ written bytes.Buffer
2108+ }
2109+
2110+ func (c * noReadFromConn ) Read (_ []byte ) (int , error ) { return 0 , io .EOF }
2111+ func (c * noReadFromConn ) Write (p []byte ) (int , error ) {
2112+ return c .written .Write (p )
2113+ }
2114+ func (c * noReadFromConn ) Close () error { return nil }
2115+ func (c * noReadFromConn ) LocalAddr () net.Addr { return dummyAddr ("local" ) }
2116+ func (c * noReadFromConn ) RemoteAddr () net.Addr { return dummyAddr ("remote" ) }
2117+ func (c * noReadFromConn ) SetDeadline (time.Time ) error { return nil }
2118+ func (c * noReadFromConn ) SetReadDeadline (time.Time ) error {
2119+ return nil
2120+ }
2121+ func (c * noReadFromConn ) SetWriteDeadline (time.Time ) error {
2122+ return nil
2123+ }
2124+
2125+ type dummyAddr string
2126+
2127+ func (a dummyAddr ) Network () string { return "dummy" }
2128+ func (a dummyAddr ) String () string { return string (a ) }
2129+
20412130func (c * testConn ) ReadFrom (r io.Reader ) (int64 , error ) {
20422131 c .readFromCalledWith = r
20432132 b , err := io .ReadAll (r )
@@ -2095,6 +2184,127 @@ func TestCopyFromWrappedConnectionToWrappedConnection(t *testing.T) {
20952184 }
20962185}
20972186
2187+ func TestDeadlineWrappersDelegate (t * testing.T ) {
2188+ conn := & deadlineConn {}
2189+ proxyConn := NewConn (conn )
2190+
2191+ deadline := time .Now ().Add (2 * time .Second )
2192+ readDeadline := time .Now ().Add (3 * time .Second )
2193+ writeDeadline := time .Now ().Add (4 * time .Second )
2194+
2195+ // Ensure deadline setters pass through to the underlying connection.
2196+ if err := proxyConn .SetDeadline (deadline ); err != nil {
2197+ t .Fatalf ("unexpected SetDeadline error: %v" , err )
2198+ }
2199+ if err := proxyConn .SetReadDeadline (readDeadline ); err != nil {
2200+ t .Fatalf ("unexpected SetReadDeadline error: %v" , err )
2201+ }
2202+ if err := proxyConn .SetWriteDeadline (writeDeadline ); err != nil {
2203+ t .Fatalf ("unexpected SetWriteDeadline error: %v" , err )
2204+ }
2205+
2206+ if ! conn .deadline .Equal (deadline ) {
2207+ t .Fatalf ("SetDeadline did not pass through value" )
2208+ }
2209+ if ! conn .readDeadline .Equal (readDeadline ) {
2210+ t .Fatalf ("SetReadDeadline did not pass through value" )
2211+ }
2212+ if ! conn .writeDeadline .Equal (writeDeadline ) {
2213+ t .Fatalf ("SetWriteDeadline did not pass through value" )
2214+ }
2215+ }
2216+
2217+ func TestReadFromFallbackCopiesToConn (t * testing.T ) {
2218+ conn := & noReadFromConn {}
2219+ proxyConn := NewConn (conn )
2220+
2221+ payload := []byte ("payload" )
2222+ if _ , err := proxyConn .ReadFrom (bytes .NewReader (payload )); err != nil {
2223+ t .Fatalf ("unexpected ReadFrom error: %v" , err )
2224+ }
2225+
2226+ // When the inner connection does not implement io.ReaderFrom,
2227+ // ReadFrom should fall back to io.Copy and write the payload.
2228+ if ! bytes .Equal (conn .written .Bytes (), payload ) {
2229+ t .Fatalf ("unexpected write content: %q" , conn .written .String ())
2230+ }
2231+ }
2232+
2233+ func TestWriteToDrainsBufferedData (t * testing.T ) {
2234+ l , err := net .Listen ("tcp" , testLocalhostRandomPort )
2235+ if err != nil {
2236+ t .Fatalf ("err: %v" , err )
2237+ }
2238+
2239+ pl := & Listener {Listener : l }
2240+
2241+ header := & Header {
2242+ Version : 2 ,
2243+ Command : PROXY ,
2244+ TransportProtocol : TCPv4 ,
2245+ SourceAddr : & net.TCPAddr {
2246+ IP : net .ParseIP (testSourceIPv4Addr ),
2247+ Port : 1000 ,
2248+ },
2249+ DestinationAddr : & net.TCPAddr {
2250+ IP : net .ParseIP (testDestinationIPv4Addr ),
2251+ Port : 2000 ,
2252+ },
2253+ }
2254+
2255+ payload := []byte ("ping" )
2256+
2257+ cliResult := make (chan error )
2258+ go func () {
2259+ conn , err := net .Dial ("tcp" , pl .Addr ().String ())
2260+ if err != nil {
2261+ cliResult <- err
2262+ return
2263+ }
2264+
2265+ // Write the header followed by payload to populate the reader buffer.
2266+ if _ , err := header .WriteTo (conn ); err != nil {
2267+ cliResult <- err
2268+ return
2269+ }
2270+ if _ , err := conn .Write (payload ); err != nil {
2271+ cliResult <- err
2272+ return
2273+ }
2274+
2275+ // Close the client so WriteTo's io.Copy completes.
2276+ if err := conn .Close (); err != nil {
2277+ cliResult <- err
2278+ return
2279+ }
2280+
2281+ close (cliResult )
2282+ }()
2283+
2284+ conn , err := pl .Accept ()
2285+ if err != nil {
2286+ t .Fatalf ("err: %v" , err )
2287+ }
2288+ t .Cleanup (func () {
2289+ if closeErr := conn .Close (); closeErr != nil {
2290+ t .Errorf ("failed to close connection: %v" , closeErr )
2291+ }
2292+ })
2293+
2294+ var out bytes.Buffer
2295+ if _ , err := conn .(* Conn ).WriteTo (& out ); err != nil {
2296+ t .Fatalf ("unexpected WriteTo error: %v" , err )
2297+ }
2298+ if ! bytes .Equal (out .Bytes (), payload ) {
2299+ t .Fatalf ("unexpected WriteTo output: %q" , out .String ())
2300+ }
2301+
2302+ err = <- cliResult
2303+ if err != nil {
2304+ t .Fatalf ("client error: %v" , err )
2305+ }
2306+ }
2307+
20982308func benchmarkTCPProxy (size int , b * testing.B ) {
20992309 // create and start the echo backend
21002310 backend , err := net .Listen ("tcp" , testLocalhostRandomPort )
0 commit comments