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