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 %T want %T", 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
) {
341 wantErr
: badStringError("bad Content-Length", "+3"),
345 wantErr
: badStringError("bad Content-Length", "-3"),
348 // max int64, for safe conversion before returning
349 cl
: "9223372036854775807",
353 cl
: "9223372036854775808",
354 wantErr
: badStringError("bad Content-Length", "9223372036854775808"),
358 for _
, tt
:= range tests
{
359 if _
, gotErr
:= parseContentLength(tt
.cl
); !reflect
.DeepEqual(gotErr
, tt
.wantErr
) {
360 t
.Errorf("%q:\n\tgot=%v\n\twant=%v", tt
.cl
, gotErr
, tt
.wantErr
)