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