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.
19 func TestBodyReadBadTrailer(t *testing.T) {
21 src: strings.NewReader("foobar"),
22 hdr: true, // force reading the trailer
23 r: bufio.NewReader(strings.NewReader("")),
25 buf := make([]byte, 7)
26 n, err := b.Read(buf[:3])
27 got := string(buf[:n])
28 if got != "foo" || err != nil {
29 t.Fatalf(`first Read = %d (%q), %v; want 3 ("foo")`, n, got, err)
32 n, err = b.Read(buf[:])
34 if got != "bar" || err != nil {
35 t.Fatalf(`second Read = %d (%q), %v; want 3 ("bar")`, n, got, err)
38 n, err = b.Read(buf[:])
41 t.Errorf("final Read was successful (%q), expected error from trailer read", got)
45 func TestFinalChunkedBodyReadEOF(t *testing.T) {
46 res, err := ReadResponse(bufio.NewReader(strings.NewReader(
47 "HTTP/1.1 200 OK\r\n"+
48 "Transfer-Encoding: chunked\r\n"+
59 want := "Body here\ncontinued"
60 buf := make([]byte, len(want))
61 n, err := res.Body.Read(buf)
62 if n != len(want) || err != io.EOF {
63 t.Logf("body = %#v", res.Body)
64 t.Errorf("Read = %v, %v; want %d, EOF", n, err, len(want))
66 if string(buf) != want {
67 t.Errorf("buf = %q; want %q", buf, want)
71 func TestDetectInMemoryReaders(t *testing.T) {
79 {bytes.NewReader(nil), true},
80 {bytes.NewBuffer(nil), true},
81 {strings.NewReader(""), true},
83 {io.NopCloser(pr), false},
85 {io.NopCloser(bytes.NewReader(nil)), true},
86 {io.NopCloser(bytes.NewBuffer(nil)), true},
87 {io.NopCloser(strings.NewReader("")), true},
89 for i, tt := range tests {
90 got := isKnownInMemoryReader(tt.r)
92 t.Errorf("%d: got = %v; want %v", i, got, tt.want)
97 type mockTransferWriter struct {
98 CalledReader io.Reader
102 var _ io.ReaderFrom = (*mockTransferWriter)(nil)
104 func (w *mockTransferWriter) ReadFrom(r io.Reader) (int64, error) {
106 return io.Copy(io.Discard, r)
109 func (w *mockTransferWriter) Write(p []byte) (int, error) {
111 return io.Discard.Write(p)
114 func TestTransferWriterWriteBodyReaderTypes(t *testing.T) {
115 fileType := reflect.TypeOf(&os.File{})
116 bufferType := reflect.TypeOf(&bytes.Buffer{})
118 nBytes := int64(1 << 10)
119 newFileFunc := func() (r io.Reader, done func(), err error) {
120 f, err := os.CreateTemp("", "net-http-newfilefunc")
125 // Write some bytes to the file to enable reading.
126 if _, err := io.CopyN(f, rand.Reader, nBytes); err != nil {
127 return nil, nil, fmt.Errorf("failed to write data to file: %v", err)
129 if _, err := f.Seek(0, 0); err != nil {
130 return nil, nil, fmt.Errorf("failed to seek to front: %v", err)
141 newBufferFunc := func() (io.Reader, func(), error) {
142 return bytes.NewBuffer(make([]byte, nBytes)), func() {}, nil
147 bodyFunc func() (io.Reader, func(), error)
150 transferEncoding []string
152 expectedReader reflect.Type
156 name: "file, non-chunked, size set",
157 bodyFunc: newFileFunc,
159 contentLength: nBytes,
161 expectedReader: fileType,
164 name: "file, non-chunked, size set, nopCloser wrapped",
166 bodyFunc: func() (io.Reader, func(), error) {
167 r, cleanup, err := newFileFunc()
168 return io.NopCloser(r), cleanup, err
170 contentLength: nBytes,
172 expectedReader: fileType,
175 name: "file, non-chunked, negative size",
177 bodyFunc: newFileFunc,
179 expectedReader: fileType,
182 name: "file, non-chunked, CONNECT, negative size",
184 bodyFunc: newFileFunc,
186 expectedReader: fileType,
189 name: "file, chunked",
191 bodyFunc: newFileFunc,
192 transferEncoding: []string{"chunked"},
196 name: "buffer, non-chunked, size set",
197 bodyFunc: newBufferFunc,
199 contentLength: nBytes,
201 expectedReader: bufferType,
204 name: "buffer, non-chunked, size set, nopCloser wrapped",
206 bodyFunc: func() (io.Reader, func(), error) {
207 r, cleanup, err := newBufferFunc()
208 return io.NopCloser(r), cleanup, err
210 contentLength: nBytes,
212 expectedReader: bufferType,
215 name: "buffer, non-chunked, negative size",
217 bodyFunc: newBufferFunc,
222 name: "buffer, non-chunked, CONNECT, negative size",
224 bodyFunc: newBufferFunc,
229 name: "buffer, chunked",
231 bodyFunc: newBufferFunc,
232 transferEncoding: []string{"chunked"},
237 for _, tc := range cases {
238 t.Run(tc.name, func(t *testing.T) {
239 body, cleanup, err := tc.bodyFunc()
245 mw := &mockTransferWriter{}
246 tw := &transferWriter{
248 ContentLength: tc.contentLength,
249 TransferEncoding: tc.transferEncoding,
252 if err := tw.writeBody(mw); err != nil {
256 if tc.expectedReader != nil {
257 if mw.CalledReader == nil {
258 t.Fatal("did not call ReadFrom")
261 var actualReader reflect.Type
262 lr, ok := mw.CalledReader.(*io.LimitedReader)
263 if ok && tc.limitedReader {
264 actualReader = reflect.TypeOf(lr.R)
266 actualReader = reflect.TypeOf(mw.CalledReader)
269 if tc.expectedReader != actualReader {
270 t.Fatalf("got reader %s want %s", actualReader, tc.expectedReader)
274 if tc.expectedWrite && !mw.WriteCalled {
275 t.Fatal("did not invoke Write")
281 func TestParseTransferEncoding(t *testing.T) {
287 hdr: Header{"Transfer-Encoding": {"fugazi"}},
288 wantErr: &unsupportedTEError{`unsupported transfer encoding: "fugazi"`},
291 hdr: Header{"Transfer-Encoding": {"chunked, chunked", "identity", "chunked"}},
292 wantErr: &unsupportedTEError{`too many transfer encodings: ["chunked, chunked" "identity" "chunked"]`},
295 hdr: Header{"Transfer-Encoding": {""}},
296 wantErr: &unsupportedTEError{`unsupported transfer encoding: ""`},
299 hdr: Header{"Transfer-Encoding": {"chunked, identity"}},
300 wantErr: &unsupportedTEError{`unsupported transfer encoding: "chunked, identity"`},
303 hdr: Header{"Transfer-Encoding": {"chunked", "identity"}},
304 wantErr: &unsupportedTEError{`too many transfer encodings: ["chunked" "identity"]`},
307 hdr: Header{"Transfer-Encoding": {"\x0bchunked"}},
308 wantErr: &unsupportedTEError{`unsupported transfer encoding: "\vchunked"`},
311 hdr: Header{"Transfer-Encoding": {"chunked"}},
316 for i, tt := range tests {
317 tr := &transferReader{
322 gotErr := tr.parseTransferEncoding()
323 if !reflect.DeepEqual(gotErr, tt.wantErr) {
324 t.Errorf("%d.\ngot error:\n%v\nwant error:\n%v\n\n", i, gotErr, tt.wantErr)
329 // issue 39017 - disallow Content-Length values such as "+3"
330 func TestParseContentLength(t *testing.T) {
337 wantErr: badStringError("invalid empty Content-Length", ""),
345 wantErr: badStringError("bad Content-Length", "+3"),
349 wantErr: badStringError("bad Content-Length", "-3"),
352 // max int64, for safe conversion before returning
353 cl: "9223372036854775807",
357 cl: "9223372036854775808",
358 wantErr: badStringError("bad Content-Length", "9223372036854775808"),
362 for _, tt := range tests {
363 if _, gotErr := parseContentLength([]string{tt.cl}); !reflect.DeepEqual(gotErr, tt.wantErr) {
364 t.Errorf("%q:\n\tgot=%v\n\twant=%v", tt.cl, gotErr, tt.wantErr)