...

Source file src/net/sendfile_test.go

Documentation: net

		 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  }
	 381  

View as plain text