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 isResponse && (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 isResponse && noResponseBodyExpected(requestMethod) {
695 return 0, nil
696 }
697 if status/100 == 1 {
698 return 0, nil
699 }
700 switch status {
701 case 204, 304:
702 return 0, nil
703 }
704
705
706 if chunked {
707 return -1, nil
708 }
709
710
711 var cl string
712 if len(contentLens) == 1 {
713 cl = textproto.TrimString(contentLens[0])
714 }
715 if cl != "" {
716 n, err := parseContentLength(cl)
717 if err != nil {
718 return -1, err
719 }
720 return n, nil
721 }
722 header.Del("Content-Length")
723
724 if isRequest {
725
726
727
728
729
730
731
732 return 0, nil
733 }
734
735
736 return -1, nil
737 }
738
739
740
741
742 func shouldClose(major, minor int, header Header, removeCloseHeader bool) bool {
743 if major < 1 {
744 return true
745 }
746
747 conv := header["Connection"]
748 hasClose := httpguts.HeaderValuesContainsToken(conv, "close")
749 if major == 1 && minor == 0 {
750 return hasClose || !httpguts.HeaderValuesContainsToken(conv, "keep-alive")
751 }
752
753 if hasClose && removeCloseHeader {
754 header.Del("Connection")
755 }
756
757 return hasClose
758 }
759
760
761 func fixTrailer(header Header, chunked bool) (Header, error) {
762 vv, ok := header["Trailer"]
763 if !ok {
764 return nil, nil
765 }
766 if !chunked {
767
768
769
770
771
772
773
774 return nil, nil
775 }
776 header.Del("Trailer")
777
778 trailer := make(Header)
779 var err error
780 for _, v := range vv {
781 foreachHeaderElement(v, func(key string) {
782 key = CanonicalHeaderKey(key)
783 switch key {
784 case "Transfer-Encoding", "Trailer", "Content-Length":
785 if err == nil {
786 err = badStringError("bad trailer key", key)
787 return
788 }
789 }
790 trailer[key] = nil
791 })
792 }
793 if err != nil {
794 return nil, err
795 }
796 if len(trailer) == 0 {
797 return nil, nil
798 }
799 return trailer, nil
800 }
801
802
803
804
805 type body struct {
806 src io.Reader
807 hdr any
808 r *bufio.Reader
809 closing bool
810 doEarlyClose bool
811
812 mu sync.Mutex
813 sawEOF bool
814 closed bool
815 earlyClose bool
816 onHitEOF func()
817 }
818
819
820
821
822
823 var ErrBodyReadAfterClose = errors.New("http: invalid Read on closed Body")
824
825 func (b *body) Read(p []byte) (n int, err error) {
826 b.mu.Lock()
827 defer b.mu.Unlock()
828 if b.closed {
829 return 0, ErrBodyReadAfterClose
830 }
831 return b.readLocked(p)
832 }
833
834
835 func (b *body) readLocked(p []byte) (n int, err error) {
836 if b.sawEOF {
837 return 0, io.EOF
838 }
839 n, err = b.src.Read(p)
840
841 if err == io.EOF {
842 b.sawEOF = true
843
844 if b.hdr != nil {
845 if e := b.readTrailer(); e != nil {
846 err = e
847
848
849
850
851 b.sawEOF = false
852 b.closed = true
853 }
854 b.hdr = nil
855 } else {
856
857
858 if lr, ok := b.src.(*io.LimitedReader); ok && lr.N > 0 {
859 err = io.ErrUnexpectedEOF
860 }
861 }
862 }
863
864
865
866
867
868
869 if err == nil && n > 0 {
870 if lr, ok := b.src.(*io.LimitedReader); ok && lr.N == 0 {
871 err = io.EOF
872 b.sawEOF = true
873 }
874 }
875
876 if b.sawEOF && b.onHitEOF != nil {
877 b.onHitEOF()
878 }
879
880 return n, err
881 }
882
883 var (
884 singleCRLF = []byte("\r\n")
885 doubleCRLF = []byte("\r\n\r\n")
886 )
887
888 func seeUpcomingDoubleCRLF(r *bufio.Reader) bool {
889 for peekSize := 4; ; peekSize++ {
890
891
892 buf, err := r.Peek(peekSize)
893 if bytes.HasSuffix(buf, doubleCRLF) {
894 return true
895 }
896 if err != nil {
897 break
898 }
899 }
900 return false
901 }
902
903 var errTrailerEOF = errors.New("http: unexpected EOF reading trailer")
904
905 func (b *body) readTrailer() error {
906
907 buf, err := b.r.Peek(2)
908 if bytes.Equal(buf, singleCRLF) {
909 b.r.Discard(2)
910 return nil
911 }
912 if len(buf) < 2 {
913 return errTrailerEOF
914 }
915 if err != nil {
916 return err
917 }
918
919
920
921
922
923
924
925
926
927 if !seeUpcomingDoubleCRLF(b.r) {
928 return errors.New("http: suspiciously long trailer after chunked body")
929 }
930
931 hdr, err := textproto.NewReader(b.r).ReadMIMEHeader()
932 if err != nil {
933 if err == io.EOF {
934 return errTrailerEOF
935 }
936 return err
937 }
938 switch rr := b.hdr.(type) {
939 case *Request:
940 mergeSetHeader(&rr.Trailer, Header(hdr))
941 case *Response:
942 mergeSetHeader(&rr.Trailer, Header(hdr))
943 }
944 return nil
945 }
946
947 func mergeSetHeader(dst *Header, src Header) {
948 if *dst == nil {
949 *dst = src
950 return
951 }
952 for k, vv := range src {
953 (*dst)[k] = vv
954 }
955 }
956
957
958
959
960 func (b *body) unreadDataSizeLocked() int64 {
961 if lr, ok := b.src.(*io.LimitedReader); ok {
962 return lr.N
963 }
964 return -1
965 }
966
967 func (b *body) Close() error {
968 b.mu.Lock()
969 defer b.mu.Unlock()
970 if b.closed {
971 return nil
972 }
973 var err error
974 switch {
975 case b.sawEOF:
976
977 case b.hdr == nil && b.closing:
978
979
980 case b.doEarlyClose:
981
982
983 if lr, ok := b.src.(*io.LimitedReader); ok && lr.N > maxPostHandlerReadBytes {
984
985
986 b.earlyClose = true
987 } else {
988 var n int64
989
990
991 n, err = io.CopyN(io.Discard, bodyLocked{b}, maxPostHandlerReadBytes)
992 if err == io.EOF {
993 err = nil
994 }
995 if n == maxPostHandlerReadBytes {
996 b.earlyClose = true
997 }
998 }
999 default:
1000
1001
1002 _, err = io.Copy(io.Discard, bodyLocked{b})
1003 }
1004 b.closed = true
1005 return err
1006 }
1007
1008 func (b *body) didEarlyClose() bool {
1009 b.mu.Lock()
1010 defer b.mu.Unlock()
1011 return b.earlyClose
1012 }
1013
1014
1015
1016 func (b *body) bodyRemains() bool {
1017 b.mu.Lock()
1018 defer b.mu.Unlock()
1019 return !b.sawEOF
1020 }
1021
1022 func (b *body) registerOnHitEOF(fn func()) {
1023 b.mu.Lock()
1024 defer b.mu.Unlock()
1025 b.onHitEOF = fn
1026 }
1027
1028
1029
1030 type bodyLocked struct {
1031 b *body
1032 }
1033
1034 func (bl bodyLocked) Read(p []byte) (n int, err error) {
1035 if bl.b.closed {
1036 return 0, ErrBodyReadAfterClose
1037 }
1038 return bl.b.readLocked(p)
1039 }
1040
1041
1042
1043 func parseContentLength(cl string) (int64, error) {
1044 cl = textproto.TrimString(cl)
1045 if cl == "" {
1046 return -1, nil
1047 }
1048 n, err := strconv.ParseUint(cl, 10, 63)
1049 if err != nil {
1050 return 0, badStringError("bad Content-Length", cl)
1051 }
1052 return int64(n), nil
1053
1054 }
1055
1056
1057
1058 type finishAsyncByteRead struct {
1059 tw *transferWriter
1060 }
1061
1062 func (fr finishAsyncByteRead) Read(p []byte) (n int, err error) {
1063 if len(p) == 0 {
1064 return
1065 }
1066 rres := <-fr.tw.ByteReadCh
1067 n, err = rres.n, rres.err
1068 if n == 1 {
1069 p[0] = rres.b
1070 }
1071 if err == nil {
1072 err = io.EOF
1073 }
1074 return
1075 }
1076
1077 var nopCloserType = reflect.TypeOf(io.NopCloser(nil))
1078 var nopCloserWriterToType = reflect.TypeOf(io.NopCloser(struct {
1079 io.Reader
1080 io.WriterTo
1081 }{}))
1082
1083
1084
1085 func unwrapNopCloser(r io.Reader) (underlyingReader io.Reader, isNopCloser bool) {
1086 switch reflect.TypeOf(r) {
1087 case nopCloserType, nopCloserWriterToType:
1088 return reflect.ValueOf(r).Field(0).Interface().(io.Reader), true
1089 default:
1090 return nil, false
1091 }
1092 }
1093
1094
1095
1096
1097 func isKnownInMemoryReader(r io.Reader) bool {
1098 switch r.(type) {
1099 case *bytes.Reader, *bytes.Buffer, *strings.Reader:
1100 return true
1101 }
1102 if r, ok := unwrapNopCloser(r); ok {
1103 return isKnownInMemoryReader(r)
1104 }
1105 if r, ok := r.(*readTrackingBody); ok {
1106 return isKnownInMemoryReader(r.ReadCloser)
1107 }
1108 return false
1109 }
1110
1111
1112
1113 type bufioFlushWriter struct{ w io.Writer }
1114
1115 func (fw bufioFlushWriter) Write(p []byte) (n int, err error) {
1116 n, err = fw.w.Write(p)
1117 if bw, ok := fw.w.(*bufio.Writer); n > 0 && ok {
1118 ferr := bw.Flush()
1119 if ferr != nil && err == nil {
1120 err = ferr
1121 }
1122 }
1123 return
1124 }
1125
View as plain text