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