github.com/guyezi/gofrontend@v0.0.0-20200228202240-7a62a49e62c0/libgo/go/net/http/transfer_test.go (about)

     1  // Copyright 2012 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  package http
     6  
     7  import (
     8  	"bufio"
     9  	"bytes"
    10  	"crypto/rand"
    11  	"fmt"
    12  	"io"
    13  	"io/ioutil"
    14  	"os"
    15  	"reflect"
    16  	"strings"
    17  	"testing"
    18  )
    19  
    20  func TestBodyReadBadTrailer(t *testing.T) {
    21  	b := &body{
    22  		src: strings.NewReader("foobar"),
    23  		hdr: true, // force reading the trailer
    24  		r:   bufio.NewReader(strings.NewReader("")),
    25  	}
    26  	buf := make([]byte, 7)
    27  	n, err := b.Read(buf[:3])
    28  	got := string(buf[:n])
    29  	if got != "foo" || err != nil {
    30  		t.Fatalf(`first Read = %d (%q), %v; want 3 ("foo")`, n, got, err)
    31  	}
    32  
    33  	n, err = b.Read(buf[:])
    34  	got = string(buf[:n])
    35  	if got != "bar" || err != nil {
    36  		t.Fatalf(`second Read = %d (%q), %v; want 3 ("bar")`, n, got, err)
    37  	}
    38  
    39  	n, err = b.Read(buf[:])
    40  	got = string(buf[:n])
    41  	if err == nil {
    42  		t.Errorf("final Read was successful (%q), expected error from trailer read", got)
    43  	}
    44  }
    45  
    46  func TestFinalChunkedBodyReadEOF(t *testing.T) {
    47  	res, err := ReadResponse(bufio.NewReader(strings.NewReader(
    48  		"HTTP/1.1 200 OK\r\n"+
    49  			"Transfer-Encoding: chunked\r\n"+
    50  			"\r\n"+
    51  			"0a\r\n"+
    52  			"Body here\n\r\n"+
    53  			"09\r\n"+
    54  			"continued\r\n"+
    55  			"0\r\n"+
    56  			"\r\n")), nil)
    57  	if err != nil {
    58  		t.Fatal(err)
    59  	}
    60  	want := "Body here\ncontinued"
    61  	buf := make([]byte, len(want))
    62  	n, err := res.Body.Read(buf)
    63  	if n != len(want) || err != io.EOF {
    64  		t.Logf("body = %#v", res.Body)
    65  		t.Errorf("Read = %v, %v; want %d, EOF", n, err, len(want))
    66  	}
    67  	if string(buf) != want {
    68  		t.Errorf("buf = %q; want %q", buf, want)
    69  	}
    70  }
    71  
    72  func TestDetectInMemoryReaders(t *testing.T) {
    73  	pr, _ := io.Pipe()
    74  	tests := []struct {
    75  		r    io.Reader
    76  		want bool
    77  	}{
    78  		{pr, false},
    79  
    80  		{bytes.NewReader(nil), true},
    81  		{bytes.NewBuffer(nil), true},
    82  		{strings.NewReader(""), true},
    83  
    84  		{ioutil.NopCloser(pr), false},
    85  
    86  		{ioutil.NopCloser(bytes.NewReader(nil)), true},
    87  		{ioutil.NopCloser(bytes.NewBuffer(nil)), true},
    88  		{ioutil.NopCloser(strings.NewReader("")), true},
    89  	}
    90  	for i, tt := range tests {
    91  		got := isKnownInMemoryReader(tt.r)
    92  		if got != tt.want {
    93  			t.Errorf("%d: got = %v; want %v", i, got, tt.want)
    94  		}
    95  	}
    96  }
    97  
    98  type mockTransferWriter struct {
    99  	CalledReader io.Reader
   100  	WriteCalled  bool
   101  }
   102  
   103  var _ io.ReaderFrom = (*mockTransferWriter)(nil)
   104  
   105  func (w *mockTransferWriter) ReadFrom(r io.Reader) (int64, error) {
   106  	w.CalledReader = r
   107  	return io.Copy(ioutil.Discard, r)
   108  }
   109  
   110  func (w *mockTransferWriter) Write(p []byte) (int, error) {
   111  	w.WriteCalled = true
   112  	return ioutil.Discard.Write(p)
   113  }
   114  
   115  func TestTransferWriterWriteBodyReaderTypes(t *testing.T) {
   116  	fileType := reflect.TypeOf(&os.File{})
   117  	bufferType := reflect.TypeOf(&bytes.Buffer{})
   118  
   119  	nBytes := int64(1 << 10)
   120  	newFileFunc := func() (r io.Reader, done func(), err error) {
   121  		f, err := ioutil.TempFile("", "net-http-newfilefunc")
   122  		if err != nil {
   123  			return nil, nil, err
   124  		}
   125  
   126  		// Write some bytes to the file to enable reading.
   127  		if _, err := io.CopyN(f, rand.Reader, nBytes); err != nil {
   128  			return nil, nil, fmt.Errorf("failed to write data to file: %v", err)
   129  		}
   130  		if _, err := f.Seek(0, 0); err != nil {
   131  			return nil, nil, fmt.Errorf("failed to seek to front: %v", err)
   132  		}
   133  
   134  		done = func() {
   135  			f.Close()
   136  			os.Remove(f.Name())
   137  		}
   138  
   139  		return f, done, nil
   140  	}
   141  
   142  	newBufferFunc := func() (io.Reader, func(), error) {
   143  		return bytes.NewBuffer(make([]byte, nBytes)), func() {}, nil
   144  	}
   145  
   146  	cases := []struct {
   147  		name             string
   148  		bodyFunc         func() (io.Reader, func(), error)
   149  		method           string
   150  		contentLength    int64
   151  		transferEncoding []string
   152  		limitedReader    bool
   153  		expectedReader   reflect.Type
   154  		expectedWrite    bool
   155  	}{
   156  		{
   157  			name:           "file, non-chunked, size set",
   158  			bodyFunc:       newFileFunc,
   159  			method:         "PUT",
   160  			contentLength:  nBytes,
   161  			limitedReader:  true,
   162  			expectedReader: fileType,
   163  		},
   164  		{
   165  			name:   "file, non-chunked, size set, nopCloser wrapped",
   166  			method: "PUT",
   167  			bodyFunc: func() (io.Reader, func(), error) {
   168  				r, cleanup, err := newFileFunc()
   169  				return ioutil.NopCloser(r), cleanup, err
   170  			},
   171  			contentLength:  nBytes,
   172  			limitedReader:  true,
   173  			expectedReader: fileType,
   174  		},
   175  		{
   176  			name:           "file, non-chunked, negative size",
   177  			method:         "PUT",
   178  			bodyFunc:       newFileFunc,
   179  			contentLength:  -1,
   180  			expectedReader: fileType,
   181  		},
   182  		{
   183  			name:           "file, non-chunked, CONNECT, negative size",
   184  			method:         "CONNECT",
   185  			bodyFunc:       newFileFunc,
   186  			contentLength:  -1,
   187  			expectedReader: fileType,
   188  		},
   189  		{
   190  			name:             "file, chunked",
   191  			method:           "PUT",
   192  			bodyFunc:         newFileFunc,
   193  			transferEncoding: []string{"chunked"},
   194  			expectedWrite:    true,
   195  		},
   196  		{
   197  			name:           "buffer, non-chunked, size set",
   198  			bodyFunc:       newBufferFunc,
   199  			method:         "PUT",
   200  			contentLength:  nBytes,
   201  			limitedReader:  true,
   202  			expectedReader: bufferType,
   203  		},
   204  		{
   205  			name:   "buffer, non-chunked, size set, nopCloser wrapped",
   206  			method: "PUT",
   207  			bodyFunc: func() (io.Reader, func(), error) {
   208  				r, cleanup, err := newBufferFunc()
   209  				return ioutil.NopCloser(r), cleanup, err
   210  			},
   211  			contentLength:  nBytes,
   212  			limitedReader:  true,
   213  			expectedReader: bufferType,
   214  		},
   215  		{
   216  			name:          "buffer, non-chunked, negative size",
   217  			method:        "PUT",
   218  			bodyFunc:      newBufferFunc,
   219  			contentLength: -1,
   220  			expectedWrite: true,
   221  		},
   222  		{
   223  			name:          "buffer, non-chunked, CONNECT, negative size",
   224  			method:        "CONNECT",
   225  			bodyFunc:      newBufferFunc,
   226  			contentLength: -1,
   227  			expectedWrite: true,
   228  		},
   229  		{
   230  			name:             "buffer, chunked",
   231  			method:           "PUT",
   232  			bodyFunc:         newBufferFunc,
   233  			transferEncoding: []string{"chunked"},
   234  			expectedWrite:    true,
   235  		},
   236  	}
   237  
   238  	for _, tc := range cases {
   239  		t.Run(tc.name, func(t *testing.T) {
   240  			body, cleanup, err := tc.bodyFunc()
   241  			if err != nil {
   242  				t.Fatal(err)
   243  			}
   244  			defer cleanup()
   245  
   246  			mw := &mockTransferWriter{}
   247  			tw := &transferWriter{
   248  				Body:             body,
   249  				ContentLength:    tc.contentLength,
   250  				TransferEncoding: tc.transferEncoding,
   251  			}
   252  
   253  			if err := tw.writeBody(mw); err != nil {
   254  				t.Fatal(err)
   255  			}
   256  
   257  			if tc.expectedReader != nil {
   258  				if mw.CalledReader == nil {
   259  					t.Fatal("did not call ReadFrom")
   260  				}
   261  
   262  				var actualReader reflect.Type
   263  				lr, ok := mw.CalledReader.(*io.LimitedReader)
   264  				if ok && tc.limitedReader {
   265  					actualReader = reflect.TypeOf(lr.R)
   266  				} else {
   267  					actualReader = reflect.TypeOf(mw.CalledReader)
   268  				}
   269  
   270  				if tc.expectedReader != actualReader {
   271  					t.Fatalf("got reader %T want %T", actualReader, tc.expectedReader)
   272  				}
   273  			}
   274  
   275  			if tc.expectedWrite && !mw.WriteCalled {
   276  				t.Fatal("did not invoke Write")
   277  			}
   278  		})
   279  	}
   280  }
   281  
   282  func TestFixTransferEncoding(t *testing.T) {
   283  	tests := []struct {
   284  		hdr     Header
   285  		wantErr error
   286  	}{
   287  		{
   288  			hdr:     Header{"Transfer-Encoding": {"fugazi"}},
   289  			wantErr: &unsupportedTEError{`unsupported transfer encoding: "fugazi"`},
   290  		},
   291  		{
   292  			hdr:     Header{"Transfer-Encoding": {"chunked, chunked", "identity", "chunked"}},
   293  			wantErr: &badStringError{"too many transfer encodings", "chunked,chunked"},
   294  		},
   295  		{
   296  			hdr:     Header{"Transfer-Encoding": {"chunked"}},
   297  			wantErr: nil,
   298  		},
   299  	}
   300  
   301  	for i, tt := range tests {
   302  		tr := &transferReader{
   303  			Header:     tt.hdr,
   304  			ProtoMajor: 1,
   305  			ProtoMinor: 1,
   306  		}
   307  		gotErr := tr.fixTransferEncoding()
   308  		if !reflect.DeepEqual(gotErr, tt.wantErr) {
   309  			t.Errorf("%d.\ngot error:\n%v\nwant error:\n%v\n\n", i, gotErr, tt.wantErr)
   310  		}
   311  	}
   312  }