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  }