github.com/code-reading/golang@v0.0.0-20220303082512-ba5bc0e589a3/go/src/net/sendfile_test.go (about) 1 // Copyright 2016 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build !js 6 // +build !js 7 8 package net 9 10 import ( 11 "bytes" 12 "crypto/sha256" 13 "encoding/hex" 14 "errors" 15 "fmt" 16 "io" 17 "os" 18 "runtime" 19 "sync" 20 "testing" 21 "time" 22 ) 23 24 const ( 25 newton = "../testdata/Isaac.Newton-Opticks.txt" 26 newtonLen = 567198 27 newtonSHA256 = "d4a9ac22462b35e7821a4f2706c211093da678620a8f9997989ee7cf8d507bbd" 28 ) 29 30 func TestSendfile(t *testing.T) { 31 ln, err := newLocalListener("tcp") 32 if err != nil { 33 t.Fatal(err) 34 } 35 defer ln.Close() 36 37 errc := make(chan error, 1) 38 go func(ln Listener) { 39 // Wait for a connection. 40 conn, err := ln.Accept() 41 if err != nil { 42 errc <- err 43 close(errc) 44 return 45 } 46 47 go func() { 48 defer close(errc) 49 defer conn.Close() 50 51 f, err := os.Open(newton) 52 if err != nil { 53 errc <- err 54 return 55 } 56 defer f.Close() 57 58 // Return file data using io.Copy, which should use 59 // sendFile if available. 60 sbytes, err := io.Copy(conn, f) 61 if err != nil { 62 errc <- err 63 return 64 } 65 66 if sbytes != newtonLen { 67 errc <- fmt.Errorf("sent %d bytes; expected %d", sbytes, newtonLen) 68 return 69 } 70 }() 71 }(ln) 72 73 // Connect to listener to retrieve file and verify digest matches 74 // expected. 75 c, err := Dial("tcp", ln.Addr().String()) 76 if err != nil { 77 t.Fatal(err) 78 } 79 defer c.Close() 80 81 h := sha256.New() 82 rbytes, err := io.Copy(h, c) 83 if err != nil { 84 t.Error(err) 85 } 86 87 if rbytes != newtonLen { 88 t.Errorf("received %d bytes; expected %d", rbytes, newtonLen) 89 } 90 91 if res := hex.EncodeToString(h.Sum(nil)); res != newtonSHA256 { 92 t.Error("retrieved data hash did not match") 93 } 94 95 for err := range errc { 96 t.Error(err) 97 } 98 } 99 100 func TestSendfileParts(t *testing.T) { 101 ln, err := newLocalListener("tcp") 102 if err != nil { 103 t.Fatal(err) 104 } 105 defer ln.Close() 106 107 errc := make(chan error, 1) 108 go func(ln Listener) { 109 // Wait for a connection. 110 conn, err := ln.Accept() 111 if err != nil { 112 errc <- err 113 close(errc) 114 return 115 } 116 117 go func() { 118 defer close(errc) 119 defer conn.Close() 120 121 f, err := os.Open(newton) 122 if err != nil { 123 errc <- err 124 return 125 } 126 defer f.Close() 127 128 for i := 0; i < 3; i++ { 129 // Return file data using io.CopyN, which should use 130 // sendFile if available. 131 _, err = io.CopyN(conn, f, 3) 132 if err != nil { 133 errc <- err 134 return 135 } 136 } 137 }() 138 }(ln) 139 140 c, err := Dial("tcp", ln.Addr().String()) 141 if err != nil { 142 t.Fatal(err) 143 } 144 defer c.Close() 145 146 buf := new(bytes.Buffer) 147 buf.ReadFrom(c) 148 149 if want, have := "Produced ", buf.String(); have != want { 150 t.Errorf("unexpected server reply %q, want %q", have, want) 151 } 152 153 for err := range errc { 154 t.Error(err) 155 } 156 } 157 158 func TestSendfileSeeked(t *testing.T) { 159 ln, err := newLocalListener("tcp") 160 if err != nil { 161 t.Fatal(err) 162 } 163 defer ln.Close() 164 165 const seekTo = 65 << 10 166 const sendSize = 10 << 10 167 168 errc := make(chan error, 1) 169 go func(ln Listener) { 170 // Wait for a connection. 171 conn, err := ln.Accept() 172 if err != nil { 173 errc <- err 174 close(errc) 175 return 176 } 177 178 go func() { 179 defer close(errc) 180 defer conn.Close() 181 182 f, err := os.Open(newton) 183 if err != nil { 184 errc <- err 185 return 186 } 187 defer f.Close() 188 if _, err := f.Seek(seekTo, os.SEEK_SET); err != nil { 189 errc <- err 190 return 191 } 192 193 _, err = io.CopyN(conn, f, sendSize) 194 if err != nil { 195 errc <- err 196 return 197 } 198 }() 199 }(ln) 200 201 c, err := Dial("tcp", ln.Addr().String()) 202 if err != nil { 203 t.Fatal(err) 204 } 205 defer c.Close() 206 207 buf := new(bytes.Buffer) 208 buf.ReadFrom(c) 209 210 if buf.Len() != sendSize { 211 t.Errorf("Got %d bytes; want %d", buf.Len(), sendSize) 212 } 213 214 for err := range errc { 215 t.Error(err) 216 } 217 } 218 219 // Test that sendfile doesn't put a pipe into blocking mode. 220 func TestSendfilePipe(t *testing.T) { 221 switch runtime.GOOS { 222 case "plan9", "windows": 223 // These systems don't support deadlines on pipes. 224 t.Skipf("skipping on %s", runtime.GOOS) 225 } 226 227 t.Parallel() 228 229 ln, err := newLocalListener("tcp") 230 if err != nil { 231 t.Fatal(err) 232 } 233 defer ln.Close() 234 235 r, w, err := os.Pipe() 236 if err != nil { 237 t.Fatal(err) 238 } 239 defer w.Close() 240 defer r.Close() 241 242 copied := make(chan bool) 243 244 var wg sync.WaitGroup 245 wg.Add(1) 246 go func() { 247 // Accept a connection and copy 1 byte from the read end of 248 // the pipe to the connection. This will call into sendfile. 249 defer wg.Done() 250 conn, err := ln.Accept() 251 if err != nil { 252 t.Error(err) 253 return 254 } 255 defer conn.Close() 256 _, err = io.CopyN(conn, r, 1) 257 if err != nil { 258 t.Error(err) 259 return 260 } 261 // Signal the main goroutine that we've copied the byte. 262 close(copied) 263 }() 264 265 wg.Add(1) 266 go func() { 267 // Write 1 byte to the write end of the pipe. 268 defer wg.Done() 269 _, err := w.Write([]byte{'a'}) 270 if err != nil { 271 t.Error(err) 272 } 273 }() 274 275 wg.Add(1) 276 go func() { 277 // Connect to the server started two goroutines up and 278 // discard any data that it writes. 279 defer wg.Done() 280 conn, err := Dial("tcp", ln.Addr().String()) 281 if err != nil { 282 t.Error(err) 283 return 284 } 285 defer conn.Close() 286 io.Copy(io.Discard, conn) 287 }() 288 289 // Wait for the byte to be copied, meaning that sendfile has 290 // been called on the pipe. 291 <-copied 292 293 // Set a very short deadline on the read end of the pipe. 294 if err := r.SetDeadline(time.Now().Add(time.Microsecond)); err != nil { 295 t.Fatal(err) 296 } 297 298 wg.Add(1) 299 go func() { 300 // Wait for much longer than the deadline and write a byte 301 // to the pipe. 302 defer wg.Done() 303 time.Sleep(50 * time.Millisecond) 304 w.Write([]byte{'b'}) 305 }() 306 307 // If this read does not time out, the pipe was incorrectly 308 // put into blocking mode. 309 _, err = r.Read(make([]byte, 1)) 310 if err == nil { 311 t.Error("Read did not time out") 312 } else if !os.IsTimeout(err) { 313 t.Errorf("got error %v, expected a time out", err) 314 } 315 316 wg.Wait() 317 } 318 319 // Issue 43822: tests that returns EOF when conn write timeout. 320 func TestSendfileOnWriteTimeoutExceeded(t *testing.T) { 321 ln, err := newLocalListener("tcp") 322 if err != nil { 323 t.Fatal(err) 324 } 325 defer ln.Close() 326 327 errc := make(chan error, 1) 328 go func(ln Listener) (retErr error) { 329 defer func() { 330 errc <- retErr 331 close(errc) 332 }() 333 334 conn, err := ln.Accept() 335 if err != nil { 336 return err 337 } 338 defer conn.Close() 339 340 // Set the write deadline in the past(1h ago). It makes 341 // sure that it is always write timeout. 342 if err := conn.SetWriteDeadline(time.Now().Add(-1 * time.Hour)); err != nil { 343 return err 344 } 345 346 f, err := os.Open(newton) 347 if err != nil { 348 return err 349 } 350 defer f.Close() 351 352 _, err = io.Copy(conn, f) 353 if errors.Is(err, os.ErrDeadlineExceeded) { 354 return nil 355 } 356 357 if err == nil { 358 err = fmt.Errorf("expected ErrDeadlineExceeded, but got nil") 359 } 360 return err 361 }(ln) 362 363 conn, err := Dial("tcp", ln.Addr().String()) 364 if err != nil { 365 t.Fatal(err) 366 } 367 defer conn.Close() 368 369 n, err := io.Copy(io.Discard, conn) 370 if err != nil { 371 t.Fatalf("expected nil error, but got %v", err) 372 } 373 if n != 0 { 374 t.Fatalf("expected receive zero, but got %d byte(s)", n) 375 } 376 377 if err := <-errc; err != nil { 378 t.Fatal(err) 379 } 380 }