Source file
src/net/http/transfer.go
1
2
3
4
5 package http
6
7 import (
8 "bufio"
9 "bytes"
10 "errors"
11 "fmt"
12 "io"
13 "net/http/httptrace"
14 "net/http/internal"
15 "net/http/internal/ascii"
16 "net/textproto"
17 "reflect"
18 "sort"
19 "strconv"
20 "strings"
21 "sync"
22 "time"
23
24 "golang.org/x/net/http/httpguts"
25 )
26
27
28
29 var ErrLineTooLong = internal.ErrLineTooLong
30
31 type errorReader struct {
32 err error
33 }
34
35 func (r errorReader) Read(p []byte) (n int, err error) {
36 return 0, r.err
37 }
38
39 type byteReader struct {
40 b byte
41 done bool
42 }
43
44 func (br *byteReader) Read(p []byte) (n int, err error) {
45 if br.done {
46 return 0, io.EOF
47 }
48 if len(p) == 0 {
49 return 0, nil
50 }
51 br.done = true
52 p[0] = br.b
53 return 1, io.EOF
54 }
55
56
57
58
59 type transferWriter struct {
60 Method string
61 Body io.Reader
62 BodyCloser io.Closer
63 ResponseToHEAD bool
64 ContentLength int64
65 Close bool
66 TransferEncoding []string
67 Header Header
68 Trailer Header
69 IsResponse bool
70 bodyReadError error
71
72 FlushHeaders bool
73 ByteReadCh chan readResult
74 }
75
76 func newTransferWriter(r any) (t *transferWriter, err error) {
77 t = &transferWriter{}
78
79
80 atLeastHTTP11 := false
81 switch rr := r.(type) {
82 case *Request:
83 if rr.ContentLength != 0 && rr.Body == nil {
84 return nil, fmt.Errorf("http: Request.ContentLength=%d with nil Body", rr.ContentLength)
85 }
86 t.Method = valueOrDefault(rr.Method, "GET")
87 t.Close = rr.Close
88 t.TransferEncoding = rr.TransferEncoding
89 t.Header = rr.Header
90 t.Trailer = rr.Trailer
91 t.Body = rr.Body
92 t.BodyCloser = rr.Body
93 t.ContentLength = rr.outgoingLength()
94 if t.ContentLength < 0 && len(t.TransferEncoding) == 0 && t.shouldSendChunkedRequestBody() {
95 t.TransferEncoding = []string{"chunked"}
96 }
97
98
99
100
101
102
103
104 if t.ContentLength != 0 && !isKnownInMemoryReader(t.Body) {
105 t.FlushHeaders = true
106 }
107
108 atLeastHTTP11 = true
109 case *Response:
110 t.IsResponse = true
111 if rr.Request != nil {
112 t.Method = rr.Request.Method
113 }
114 t.Body = rr.Body
115 t.BodyCloser = rr.Body
116 t.ContentLength = rr.ContentLength
117 t.Close = rr.Close
118 t.TransferEncoding = rr.TransferEncoding
119 t.Header = rr.Header
120 t.Trailer = rr.Trailer
121 atLeastHTTP11 = rr.ProtoAtLeast(1, 1)
122 t.ResponseToHEAD = noResponseBodyExpected(t.Method)
123 }
124
125
126 if t.ResponseToHEAD {
127 t.Body = nil
128 if chunked(t.TransferEncoding) {
129 t.ContentLength = -1
130 }
131 } else {
132 if !atLeastHTTP11 || t.Body == nil {
133 t.TransferEncoding = nil
134 }
135 if chunked(t.TransferEncoding) {
136 t.ContentLength = -1
137 } else if t.Body == nil {
138 t.ContentLength = 0
139 }
140 }
141
142
143 if !chunked(t.TransferEncoding) {
144 t.Trailer = nil
145 }
146
147 return t, nil
148 }
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168 func (t *transferWriter) shouldSendChunkedRequestBody() bool {
169
170
171 if t.ContentLength >= 0 || t.Body == nil {
172 return false
173 }
174 if t.Method == "CONNECT" {
175 return false
176 }
177 if requestMethodUsuallyLacksBody(t.Method) {
178
179
180
181 t.probeRequestBody()
182 return t.Body != nil
183 }
184
185
186
187
188 return true
189 }
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206 func (t *transferWriter) probeRequestBody() {
207 t.ByteReadCh = make(chan readResult, 1)
208 go func(body io.Reader) {
209 var buf [1]byte
210 var rres readResult
211 rres.n, rres.err = body.Read(buf[:])
212 if rres.n == 1 {
213 rres.b = buf[0]
214 }
215 t.ByteReadCh <- rres
216 close(t.ByteReadCh)
217 }(t.Body)
218 timer := time.NewTimer(200 * time.Millisecond)
219 select {
220 case rres := <-t.ByteReadCh:
221 timer.Stop()
222 if rres.n == 0 && rres.err == io.EOF {
223
224 t.Body = nil
225 t.ContentLength = 0
226 } else if rres.n == 1 {
227 if rres.err != nil {
228 t.Body = io.MultiReader(&byteReader{b: rres.b}, errorReader{rres.err})
229 } else {
230 t.Body = io.MultiReader(&byteReader{b: rres.b}, t.Body)
231 }
232 } else if rres.err != nil {
233 t.Body = errorReader{rres.err}
234 }
235 case <-timer.C:
236
237
238
239
240 t.Body = io.MultiReader(finishAsyncByteRead{t}, t.Body)
241
242
243
244 t.FlushHeaders = true
245 }
246 }
247
248 func noResponseBodyExpected(requestMethod string) bool {
249 return requestMethod == "HEAD"
250 }
251
252 func (t *transferWriter) shouldSendContentLength() bool {
253 if chunked(t.TransferEncoding) {
254 return false
255 }
256 if t.ContentLength > 0 {
257 return true
258 }
259 if t.ContentLength < 0 {
260 return false
261 }
262
263 if t.Method == "POST" || t.Method == "PUT" || t.Method == "PATCH" {
264 return true
265 }
266 if t.ContentLength == 0 && isIdentity(t.TransferEncoding) {
267 if t.Method == "GET" || t.Method == "HEAD" {
268 return false
269 }
270 return true
271 }
272
273 return false
274 }
275
276 func (t *transferWriter) writeHeader(w io.Writer, trace *httptrace.ClientTrace) error {
277 if t.Close && !hasToken(t.Header.get("Connection"), "close") {
278 if _, err := io.WriteString(w, "Connection: close\r\n"); err != nil {
279 return err
280 }
281 if trace != nil && trace.WroteHeaderField != nil {
282 trace.WroteHeaderField("Connection", []string{"close"})
283 }
284 }
285
286
287
288
289 if t.shouldSendContentLength() {
290 if _, err := io.WriteString(w, "Content-Length: "); err != nil {
291 return err
292 }
293 if _, err := io.WriteString(w, strconv.FormatInt(t.ContentLength, 10)+"\r\n"); err != nil {
294 return err
295 }
296 if trace != nil && trace.WroteHeaderField != nil {
297 trace.WroteHeaderField("Content-Length", []string{strconv.FormatInt(t.ContentLength, 10)})
298 }
299 } else if chunked(t.TransferEncoding) {
300 if _, err := io.WriteString(w, "Transfer-Encoding: chunked\r\n"); err != nil {
301 return err
302 }
303 if trace != nil && trace.WroteHeaderField != nil {
304 trace.WroteHeaderField("Transfer-Encoding", []string{"chunked"})
305 }
306 }
307
308
309 if t.Trailer != nil {
310 keys := make([]string, 0, len(t.Trailer))
311 for k := range t.Trailer {
312 k = CanonicalHeaderKey(k)
313 switch k {
314 case "Transfer-Encoding", "Trailer", "Content-Length":
315 return badStringError("invalid Trailer key", k)
316 }
317 keys = append(keys, k)
318 }
319 if len(keys) > 0 {
320 sort.Strings(keys)
321
322
323 if _, err := io.WriteString(w, "Trailer: "+strings.Join(keys, ",")+"\r\n"); err != nil {
324 return err
325 }
326 if trace != nil && trace.WroteHeaderField != nil {
327 trace.WroteHeaderField("Trailer", keys)
328 }
329 }
330 }
331
332 return nil
333 }
334
335
336 func (t *transferWriter) writeBody(w io.Writer) (err error) {
337 var ncopy int64
338 closed := false
339 defer func() {
340 if closed || t.BodyCloser == nil {
341 return
342 }
343 if closeErr := t.BodyCloser.Close(); closeErr != nil && err == nil {
344 err = closeErr
345 }
346 }()
347
348
349
350
351
352 if t.Body != nil {
353 var body = t.unwrapBody()
354 if chunked(t.TransferEncoding) {
355 if bw, ok := w.(*bufio.Writer); ok && !t.IsResponse {
356 w = &internal.FlushAfterChunkWriter{Writer: bw}
357 }
358 cw := internal.NewChunkedWriter(w)
359 _, err = t.doBodyCopy(cw, body)
360 if err == nil {
361 err = cw.Close()
362 }
363 } else if t.ContentLength == -1 {
364 dst := w
365 if t.Method == "CONNECT" {
366 dst = bufioFlushWriter{dst}
367 }
368 ncopy, err = t.doBodyCopy(dst, body)
369 } else {
370 ncopy, err = t.doBodyCopy(w, io.LimitReader(body, t.ContentLength))
371 if err != nil {
372 return err
373 }
374 var nextra int64
375 nextra, err = t.doBodyCopy(io.Discard, body)
376 ncopy += nextra
377 }
378 if err != nil {
379 return err
380 }
381 }
382 if t.BodyCloser != nil {
383 closed = true
384 if err := t.BodyCloser.Close(); err != nil {
385 return err
386 }
387 }
388
389 if !t.ResponseToHEAD && t.ContentLength != -1 && t.ContentLength != ncopy {
390 return fmt.Errorf("http: ContentLength=%d with Body length %d",
391 t.ContentLength, ncopy)
392 }
393
394 if chunked(t.TransferEncoding) {
395
396 if t.Trailer != nil {
397 if err := t.Trailer.Write(w); err != nil {
398 return err
399 }
400 }
401
402 _, err = io.WriteString(w, "\r\n")
403 }
404 return err
405 }
406
407
408
409
410
411 func (t *transferWriter) doBodyCopy(dst io.Writer, src io.Reader) (n int64, err error) {
412 n, err = io.Copy(dst, src)
413 if err != nil && err != io.EOF {
414 t.bodyReadError = err
415 }
416 return
417 }
418
419
420
421
422
423
424 func (t *transferWriter) unwrapBody() io.Reader {
425 if r, ok := unwrapNopCloser(t.Body); ok {
426 return r
427 }
428 if r, ok := t.Body.(*readTrackingBody); ok {
429 r.didRead = true
430 return r.ReadCloser
431 }
432 return t.Body
433 }
434
435 type transferReader struct {
436
437 Header Header
438 StatusCode int
439 RequestMethod string
440 ProtoMajor int
441 ProtoMinor int
442
443 Body io.ReadCloser
444 ContentLength int64
445 Chunked bool
446 Close bool
447 Trailer Header
448 }
449
450 func (t *transferReader) protoAtLeast(m, n int) bool {
451 return t.ProtoMajor > m || (t.ProtoMajor == m && t.ProtoMinor >= n)
452 }
453
454
455
456 func bodyAllowedForStatus(status int) bool {
457 switch {
458 case status >= 100 && status <= 199:
459 return false
460 case status == 204:
461 return false
462 case status == 304:
463 return false
464 }
465 return true
466 }
467
468 var (
469 suppressedHeaders304 = []string{"Content-Type", "Content-Length", "Transfer-Encoding"}
470 suppressedHeadersNoBody = []string{"Content-Length", "Transfer-Encoding"}
471 excludedHeadersNoBody = map[string]bool{"Content-Length": true, "Transfer-Encoding": true}
472 )
473
474 func suppressedHeaders(status int) []string {
475 switch {
476 case status == 304:
477
478 return suppressedHeaders304
479 case !bodyAllowedForStatus(status):
480 return suppressedHeadersNoBody
481 }
482 return nil
483 }
484
485
486 func readTransfer(msg any, r *bufio.Reader) (err error) {
487 t := &transferReader{RequestMethod: "GET"}
488
489
490 isResponse := false
491 switch rr := msg.(type) {
492 case *Response:
493 t.Header = rr.Header
494 t.StatusCode = rr.StatusCode
495 t.ProtoMajor = rr.ProtoMajor
496 t.ProtoMinor = rr.ProtoMinor
497 t.Close = shouldClose(t.ProtoMajor, t.ProtoMinor, t.Header, true)
498 isResponse = true
499 if rr.Request != nil {
500 t.RequestMethod = rr.Request.Method
501 }
502 case *Request:
503 t.Header = rr.Header
504 t.RequestMethod = rr.Method
505 t.ProtoMajor = rr.ProtoMajor
506 t.ProtoMinor = rr.ProtoMinor
507
508
509 t.StatusCode = 200
510 t.Close = rr.Close
511 default:
512 panic("unexpected type")
513 }
514
515
516 if t.ProtoMajor == 0 && t.ProtoMinor == 0 {
517 t.ProtoMajor, t.ProtoMinor = 1, 1
518 }
519
520
521 if err := t.parseTransferEncoding(); err != nil {
522 return err
523 }
524
525 realLength, err := fixLength(isResponse, t.StatusCode, t.RequestMethod, t.Header, t.Chunked)
526 if err != nil {
527 return err
528 }
529 if isResponse && t.RequestMethod == "HEAD" {
530 if n, err := parseContentLength(t.Header.get("Content-Length")); err != nil {
531 return err
532 } else {
533 t.ContentLength = n
534 }
535 } else {
536 t.ContentLength = realLength
537 }
538
539
540 t.Trailer, err = fixTrailer(t.Header, t.Chunked)
541 if err != nil {
542 return err
543 }
544
545
546
547
548 switch msg.(type) {
549 case *Response:
550 if realLength == -1 && !t.Chunked && bodyAllowedForStatus(t.StatusCode) {
551
552 t.Close = true
553 }
554 }
555
556
557
558 switch {
559 case t.Chunked:
560 if noResponseBodyExpected(t.RequestMethod) || !bodyAllowedForStatus(t.StatusCode) {
561 t.Body = NoBody
562 } else {
563 t.Body = &body{src: internal.NewChunkedReader(r), hdr: msg, r: r, closing: t.Close}
564 }
565 case realLength == 0:
566 t.Body = NoBody
567 case realLength > 0:
568 t.Body = &body{src: io.LimitReader(r, realLength), closing: t.Close}
569 default:
570
571 if t.Close {
572
573 t.Body = &body{src: r, closing: t.Close}
574 } else {
575
576 t.Body = NoBody
577 }
578 }
579
580
581 switch rr := msg.(type) {
582 case *Request:
583 rr.Body = t.Body
584 rr.ContentLength = t.ContentLength
585 if t.Chunked {
586 rr.TransferEncoding = []string{"chunked"}
587 }
588 rr.Close = t.Close
589 rr.Trailer = t.Trailer
590 case *Response:
591 rr.Body = t.Body
592 rr.ContentLength = t.ContentLength
593 if t.Chunked {
594 rr.TransferEncoding = []string{"chunked"}
595 }
596 rr.Close = t.Close
597 rr.Trailer = t.Trailer
598 }
599
600 return nil
601 }
602
603
604 func chunked(te []string) bool { return len(te) > 0 && te[0] == "chunked" }
605
606
607 func isIdentity(te []string) bool { return len(te) == 1 && te[0] == "identity" }
608
609
610 type unsupportedTEError struct {
611 err string
612 }
613
614 func (uste *unsupportedTEError) Error() string {
615 return uste.err
616 }
617
618
619
620 func isUnsupportedTEError(err error) bool {
621 _, ok := err.(*unsupportedTEError)
622 return ok
623 }
624
625
626 func (t *transferReader) parseTransferEncoding() error {
627 raw, present := t.Header["Transfer-Encoding"]
628 if !present {
629 return nil
630 }
631 delete(t.Header, "Transfer-Encoding")
632
633
634 if !t.protoAtLeast(1, 1) {
635 return nil
636 }
637
638
639
640
641
642 if len(raw) != 1 {
643 return &unsupportedTEError{fmt.Sprintf("too many transfer encodings: %q", raw)}
644 }
645 if !ascii.EqualFold(raw[0], "chunked") {
646 return &unsupportedTEError{fmt.Sprintf("unsupported transfer encoding: %q", raw[0])}
647 }
648
649
650
651
652
653
654
655
656
657
658
659
660 delete(t.Header, "Content-Length")
661
662 t.Chunked = true
663 return nil
664 }
665
666
667
668
669 func fixLength(isResponse bool, status int, requestMethod string, header Header, chunked bool) (int64, error) {
670 isRequest := !isResponse
671 contentLens := header["Content-Length"]
672
673
674 if len(contentLens) > 1 {
675
676
677
678
679 first := textproto.TrimString(contentLens[0])
680 for _, ct := range contentLens[1:] {
681 if first != textproto.TrimString(ct) {
682 return 0, fmt.Errorf("http: message cannot contain multiple Content-Length headers; got %q", contentLens)
683 }
684 }
685
686
687 header.Del("Content-Length")
688 header.Add("Content-Length", first)
689
690 contentLens = header["Content-Length"]
691 }
692
693
694 if noResponseBodyExpected(requestMethod) {
695
696
697
698
699 if isRequest && len(contentLens) > 0 && !(len(contentLens) == 1 && contentLens[0] == "0") {
700 return 0, fmt.Errorf("http: method cannot contain a Content-Length; got %q", contentLens)
701 }
702 return 0, nil
703 }
704 if status/100 == 1 {
705 return 0, nil
706 }
707 switch status {
708 case 204, 304:
709 return 0, nil
710 }
711
712
713 if chunked {
714 return -1, nil
715 }
716
717
718 var cl string
719 if len(contentLens) == 1 {
720 cl = textproto.TrimString(contentLens[0])
721 }
722 if cl != "" {
723 n, err := parseContentLength(cl)
724 if err != nil {
725 return -1, err
726 }
727 return n, nil
728 }
729 header.Del("Content-Length")
730
731 if isRequest {
732
733
734
735
736
737
738
739 return 0, nil
740 }
741
742
743 return -1, nil
744 }
745
746
747
748
749 func shouldClose(major, minor int, header Header, removeCloseHeader bool) bool {
750 if major < 1 {
751 return true
752 }
753
754 conv := header["Connection"]
755 hasClose := httpguts.HeaderValuesContainsToken(conv, "close")
756 if major == 1 && minor == 0 {
757 return hasClose || !httpguts.HeaderValuesContainsToken(conv, "keep-alive")
758 }
759
760 if hasClose && removeCloseHeader {
761 header.Del("Connection")
762 }
763
764 return hasClose
765 }
766
767
768 func fixTrailer(header Header, chunked bool) (Header, error) {
769 vv, ok := header["Trailer"]
770 if !ok {
771 return nil, nil
772 }
773 if !chunked {
774
775
776
777
778
779
780
781 return nil, nil
782 }
783 header.Del("Trailer")
784
785 trailer := make(Header)
786 var err error
787 for _, v := range vv {
788 foreachHeaderElement(v, func(key string) {
789 key = CanonicalHeaderKey(key)
790 switch key {
791 case "Transfer-Encoding", "Trailer", "Content-Length":
792 if err == nil {
793 err = badStringError("bad trailer key", key)
794 return
795 }
796 }
797 trailer[key] = nil
798 })
799 }
800 if err != nil {
801 return nil, err
802 }
803 if len(trailer) == 0 {
804 return nil, nil
805 }
806 return trailer, nil
807 }
808
809
810
811
812 type body struct {
813 src io.Reader
814 hdr any
815 r *bufio.Reader
816 closing bool
817 doEarlyClose bool
818
819 mu sync.Mutex
820 sawEOF bool
821 closed bool
822 earlyClose bool
823 onHitEOF func()
824 }
825
826
827
828
829
830 var ErrBodyReadAfterClose = errors.New("http: invalid Read on closed Body")
831
832 func (b *body) Read(p []byte) (n int, err error) {
833 b.mu.Lock()
834 defer b.mu.Unlock()
835 if b.closed {
836 return 0, ErrBodyReadAfterClose
837 }
838 return b.readLocked(p)
839 }
840
841
842 func (b *body) readLocked(p []byte) (n int, err error) {
843 if b.sawEOF {
844 return 0, io.EOF
845 }
846 n, err = b.src.Read(p)
847
848 if err == io.EOF {
849 b.sawEOF = true
850
851 if b.hdr != nil {
852 if e := b.readTrailer(); e != nil {
853 err = e
854
855
856
857
858 b.sawEOF = false
859 b.closed = true
860 }
861 b.hdr = nil
862 } else {
863
864
865 if lr, ok := b.src.(*io.LimitedReader); ok && lr.N > 0 {
866 err = io.ErrUnexpectedEOF
867 }
868 }
869 }
870
871
872
873
874
875
876 if err == nil && n > 0 {
877 if lr, ok := b.src.(*io.LimitedReader); ok && lr.N == 0 {
878 err = io.EOF
879 b.sawEOF = true
880 }
881 }
882
883 if b.sawEOF && b.onHitEOF != nil {
884 b.onHitEOF()
885 }
886
887 return n, err
888 }
889
890 var (
891 singleCRLF = []byte("\r\n")
892 doubleCRLF = []byte("\r\n\r\n")
893 )
894
895 func seeUpcomingDoubleCRLF(r *bufio.Reader) bool {
896 for peekSize := 4; ; peekSize++ {
897
898
899 buf, err := r.Peek(peekSize)
900 if bytes.HasSuffix(buf, doubleCRLF) {
901 return true
902 }
903 if err != nil {
904 break
905 }
906 }
907 return false
908 }
909
910 var errTrailerEOF = errors.New("http: unexpected EOF reading trailer")
911
912 func (b *body) readTrailer() error {
913
914 buf, err := b.r.Peek(2)
915 if bytes.Equal(buf, singleCRLF) {
916 b.r.Discard(2)
917 return nil
918 }
919 if len(buf) < 2 {
920 return errTrailerEOF
921 }
922 if err != nil {
923 return err
924 }
925
926
927
928
929
930
931
932
933
934 if !seeUpcomingDoubleCRLF(b.r) {
935 return errors.New("http: suspiciously long trailer after chunked body")
936 }
937
938 hdr, err := textproto.NewReader(b.r).ReadMIMEHeader()
939 if err != nil {
940 if err == io.EOF {
941 return errTrailerEOF
942 }
943 return err
944 }
945 switch rr := b.hdr.(type) {
946 case *Request:
947 mergeSetHeader(&rr.Trailer, Header(hdr))
948 case *Response:
949 mergeSetHeader(&rr.Trailer, Header(hdr))
950 }
951 return nil
952 }
953
954 func mergeSetHeader(dst *Header, src Header) {
955 if *dst == nil {
956 *dst = src
957 return
958 }
959 for k, vv := range src {
960 (*dst)[k] = vv
961 }
962 }
963
964
965
966
967 func (b *body) unreadDataSizeLocked() int64 {
968 if lr, ok := b.src.(*io.LimitedReader); ok {
969 return lr.N
970 }
971 return -1
972 }
973
974 func (b *body) Close() error {
975 b.mu.Lock()
976 defer b.mu.Unlock()
977 if b.closed {
978 return nil
979 }
980 var err error
981 switch {
982 case b.sawEOF:
983
984 case b.hdr == nil && b.closing:
985
986
987 case b.doEarlyClose:
988
989
990 if lr, ok := b.src.(*io.LimitedReader); ok && lr.N > maxPostHandlerReadBytes {
991
992
993 b.earlyClose = true
994 } else {
995 var n int64
996
997
998 n, err = io.CopyN(io.Discard, bodyLocked{b}, maxPostHandlerReadBytes)
999 if err == io.EOF {
1000 err = nil
1001 }
1002 if n == maxPostHandlerReadBytes {
1003 b.earlyClose = true
1004 }
1005 }
1006 default:
1007
1008
1009 _, err = io.Copy(io.Discard, bodyLocked{b})
1010 }
1011 b.closed = true
1012 return err
1013 }
1014
1015 func (b *body) didEarlyClose() bool {
1016 b.mu.Lock()
1017 defer b.mu.Unlock()
1018 return b.earlyClose
1019 }
1020
1021
1022
1023 func (b *body) bodyRemains() bool {
1024 b.mu.Lock()
1025 defer b.mu.Unlock()
1026 return !b.sawEOF
1027 }
1028
1029 func (b *body) registerOnHitEOF(fn func()) {
1030 b.mu.Lock()
1031 defer b.mu.Unlock()
1032 b.onHitEOF = fn
1033 }
1034
1035
1036
1037 type bodyLocked struct {
1038 b *body
1039 }
1040
1041 func (bl bodyLocked) Read(p []byte) (n int, err error) {
1042 if bl.b.closed {
1043 return 0, ErrBodyReadAfterClose
1044 }
1045 return bl.b.readLocked(p)
1046 }
1047
1048
1049
1050 func parseContentLength(cl string) (int64, error) {
1051 cl = textproto.TrimString(cl)
1052 if cl == "" {
1053 return -1, nil
1054 }
1055 n, err := strconv.ParseUint(cl, 10, 63)
1056 if err != nil {
1057 return 0, badStringError("bad Content-Length", cl)
1058 }
1059 return int64(n), nil
1060
1061 }
1062
1063
1064
1065 type finishAsyncByteRead struct {
1066 tw *transferWriter
1067 }
1068
1069 func (fr finishAsyncByteRead) Read(p []byte) (n int, err error) {
1070 if len(p) == 0 {
1071 return
1072 }
1073 rres := <-fr.tw.ByteReadCh
1074 n, err = rres.n, rres.err
1075 if n == 1 {
1076 p[0] = rres.b
1077 }
1078 if err == nil {
1079 err = io.EOF
1080 }
1081 return
1082 }
1083
1084 var nopCloserType = reflect.TypeOf(io.NopCloser(nil))
1085 var nopCloserWriterToType = reflect.TypeOf(io.NopCloser(struct {
1086 io.Reader
1087 io.WriterTo
1088 }{}))
1089
1090
1091
1092 func unwrapNopCloser(r io.Reader) (underlyingReader io.Reader, isNopCloser bool) {
1093 switch reflect.TypeOf(r) {
1094 case nopCloserType, nopCloserWriterToType:
1095 return reflect.ValueOf(r).Field(0).Interface().(io.Reader), true
1096 default:
1097 return nil, false
1098 }
1099 }
1100
1101
1102
1103
1104 func isKnownInMemoryReader(r io.Reader) bool {
1105 switch r.(type) {
1106 case *bytes.Reader, *bytes.Buffer, *strings.Reader:
1107 return true
1108 }
1109 if r, ok := unwrapNopCloser(r); ok {
1110 return isKnownInMemoryReader(r)
1111 }
1112 if r, ok := r.(*readTrackingBody); ok {
1113 return isKnownInMemoryReader(r.ReadCloser)
1114 }
1115 return false
1116 }
1117
1118
1119
1120 type bufioFlushWriter struct{ w io.Writer }
1121
1122 func (fw bufioFlushWriter) Write(p []byte) (n int, err error) {
1123 n, err = fw.w.Write(p)
1124 if bw, ok := fw.w.(*bufio.Writer); n > 0 && ok {
1125 ferr := bw.Flush()
1126 if ferr != nil && err == nil {
1127 err = ferr
1128 }
1129 }
1130 return
1131 }
1132
View as plain text