1
2
3
4
5 package http3
6
7 import (
8 "context"
9 "crypto/tls"
10 "errors"
11 "fmt"
12 "maps"
13 "net"
14 "net/http"
15 "net/textproto"
16 "os"
17 "slices"
18 "strconv"
19 "strings"
20 "sync"
21 "time"
22
23 "golang.org/x/net/http/httpguts"
24 "net/http/internal/httpcommon"
25 "golang.org/x/net/quic"
26 )
27
28
29
30 type server struct {
31 srv1 *http.Server
32 opts ServerOpts
33
34 initOnce sync.Once
35
36
37
38
39 connClosed chan any
40 mu sync.Mutex
41 activeConns map[*serverConn]struct{}
42 }
43
44
45
46 type netHTTPServer struct {
47 *server
48 }
49
50
51 func (netHTTPServer) Accept() (net.Conn, error) { return nil, net.ErrClosed }
52 func (netHTTPServer) Close() error { return nil }
53 func (netHTTPServer) Addr() net.Addr { return nil }
54
55
56
57
58
59 func (s netHTTPServer) ServeHTTP3(ctx context.Context, conn net.PacketConn, tlsConfig *tls.Config, h http.Handler) error {
60 s.init()
61 e, err := quic.NewEndpoint(conn, newQUICConfig(s.opts.QUICConfig, tlsConfig))
62 if err != nil {
63 return err
64 }
65 return s.serve(ctx, e, h)
66 }
67
68
69 func (s netHTTPServer) Shutdown(ctx context.Context) error {
70 s.shutdown(ctx)
71 return nil
72 }
73
74 type ServerOpts struct {
75
76
77
78
79
80 QUICConfig *quic.Config
81 }
82
83
84
85
86
87 func RegisterServer(s *http.Server, opts ServerOpts) error {
88 if err := s.Serve(netHTTPServer{&server{
89 opts: opts,
90 srv1: s,
91 }}); err != nil {
92 return errors.New("http3: net/http does not support HTTP/3")
93 }
94 return nil
95 }
96
97 func (s *server) init() {
98 s.initOnce.Do(func() {
99 s.activeConns = make(map[*serverConn]struct{})
100 s.connClosed = make(chan any, 1)
101 })
102 }
103
104
105
106 func (s *server) serve(ctx context.Context, e *quic.Endpoint, h http.Handler) error {
107 s.init()
108 defer e.Close(canceledCtx)
109 for {
110 qconn, err := e.Accept(ctx)
111 if err != nil {
112 return err
113 }
114 go s.newServerConn(ctx, qconn, h)
115 }
116 }
117
118
119 func (s *server) shutdown(ctx context.Context) {
120
121 if ctx == nil {
122 var cancel context.CancelFunc
123 ctx, cancel = context.WithTimeout(context.Background(), time.Second)
124 defer cancel()
125 }
126
127
128
129 s.mu.Lock()
130 for sc := range s.activeConns {
131
132
133 go sc.sendGoaway()
134 }
135 s.mu.Unlock()
136
137
138
139 defer func() {
140 s.mu.Lock()
141 defer s.mu.Unlock()
142 for sc := range s.activeConns {
143 sc.abort(&connectionError{
144 code: errH3NoError,
145 message: "server is shutting down",
146 })
147 }
148 }()
149 noMoreConns := func() bool {
150 s.mu.Lock()
151 defer s.mu.Unlock()
152 return len(s.activeConns) == 0
153 }
154 for {
155 if noMoreConns() {
156 return
157 }
158 select {
159 case <-ctx.Done():
160 return
161 case <-s.connClosed:
162 }
163 }
164 }
165
166 func (s *server) registerConn(sc *serverConn) {
167 s.mu.Lock()
168 defer s.mu.Unlock()
169 s.activeConns[sc] = struct{}{}
170 }
171
172 func (s *server) unregisterConn(sc *serverConn) {
173 s.mu.Lock()
174 delete(s.activeConns, sc)
175 s.mu.Unlock()
176 select {
177 case s.connClosed <- struct{}{}:
178 default:
179
180
181 }
182 }
183
184 func (s *server) readHeaderTimeout() time.Duration {
185 if s.srv1 == nil || s.srv1.ReadHeaderTimeout == 0 {
186 return s.readTimeout()
187 }
188 return s.srv1.ReadHeaderTimeout
189 }
190
191 func (s *server) readTimeout() time.Duration {
192 if s.srv1 == nil {
193 return 0
194 }
195 return s.srv1.ReadTimeout
196 }
197
198 func (s *server) writeTimeout() time.Duration {
199 if s.srv1 == nil {
200 return 0
201 }
202 return s.srv1.WriteTimeout
203 }
204
205
206 func (s *server) idleTimeout() time.Duration {
207 if s.srv1 == nil || s.srv1.IdleTimeout == 0 {
208 return s.readTimeout()
209 }
210 return s.srv1.IdleTimeout
211 }
212
213 type serverConn struct {
214 qconn *quic.Conn
215 srv *server
216 baseCtx context.Context
217 handler http.Handler
218
219 genericConn
220 enc qpackEncoder
221 dec qpackDecoder
222
223 maxHeaderBytes int64
224 maxHeaderValueCount int64
225
226
227 controlStream *stream
228 mu sync.Mutex
229 maxRequestStreamID int64
230 goawaySent bool
231 }
232
233
234
235 func (s *server) newServerConn(baseCtx context.Context, qconn *quic.Conn, h http.Handler) {
236 sc := &serverConn{
237 qconn: qconn,
238 srv: s,
239 baseCtx: baseCtx,
240 handler: h,
241 maxHeaderBytes: int64(s.srv1.MaxHeaderBytes),
242
243
244 }
245
246
247 if sc.maxHeaderBytes <= 0 {
248 sc.maxHeaderBytes = int64(http.DefaultMaxHeaderBytes)
249 }
250
251
252
253
254
255 s.registerConn(sc)
256 defer s.unregisterConn(sc)
257 sc.enc.init()
258
259
260
261 var err error
262 sc.controlStream, err = newConnStream(context.Background(), sc.qconn, streamTypeControl)
263 if err != nil {
264 return
265 }
266 sc.controlStream.writeSettings(
267 settingsMaxFieldSectionSize, sc.maxHeaderBytes,
268 )
269 sc.controlStream.Flush()
270
271 sc.acceptStreams(sc.qconn, sc)
272 }
273
274 func (sc *serverConn) handleControlStream(st *stream) error {
275
276
277 if err := st.readSettings(func(settingsType, settingsValue int64) error {
278 switch settingsType {
279 case settingsMaxFieldSectionSize:
280 _ = settingsValue
281 case settingsQPACKMaxTableCapacity:
282 _ = settingsValue
283 case settingsQPACKBlockedStreams:
284 _ = settingsValue
285 default:
286
287 }
288 return nil
289 }); err != nil {
290 return err
291 }
292
293 for {
294 ftype, err := st.readFrameHeader()
295 if err != nil {
296 return err
297 }
298 switch ftype {
299 case frameTypeCancelPush:
300
301
302
303
304 return &connectionError{
305 code: errH3IDError,
306 message: "CANCEL_PUSH for unsent push ID",
307 }
308 case frameTypeGoaway:
309 return errH3NoError
310 default:
311
312 if err := st.discardUnknownFrame(ftype); err != nil {
313 return err
314 }
315 }
316 }
317 }
318
319 func (sc *serverConn) handleEncoderStream(*stream) error {
320
321 return nil
322 }
323
324 func (sc *serverConn) handleDecoderStream(*stream) error {
325
326 return nil
327 }
328
329 func (sc *serverConn) handlePushStream(*stream) error {
330
331
332
333 return &connectionError{
334 code: errH3StreamCreationError,
335 message: "client created push stream",
336 }
337 }
338
339
340
341
342
343
344
345
346
347
348
349 func hasDisallowedConnectionHeader(h http.Header) bool {
350 neverAllowed := []string{
351 "Connection",
352 "Keep-Alive",
353 "Proxy-Connection",
354 "Transfer-Encoding",
355 "Upgrade",
356 }
357 for _, k := range neverAllowed {
358 if _, ok := h[k]; ok {
359 return true
360 }
361 }
362 if te, ok := h["Te"]; ok && (len(te) != 1 || te[0] != "trailers") {
363 return true
364 }
365 return false
366 }
367
368 type pseudoHeader struct {
369 method string
370 scheme string
371 path string
372 authority string
373 }
374
375 func (sc *serverConn) parseHeader(st *stream) (http.Header, pseudoHeader, error) {
376 ftype, err := st.readFrameHeader()
377 if err != nil {
378 return nil, pseudoHeader{}, err
379 }
380 if ftype != frameTypeHeaders {
381 return nil, pseudoHeader{}, &streamError{errH3MessageError, "received other frames when expecting HEADERS"}
382 }
383 if st.lim > sc.maxHeaderBytes {
384
385
386
387 return nil, pseudoHeader{}, &streamError{errH3RequestRejected, "headers too large"}
388 }
389 header := make(http.Header)
390 valueCount := int64(0)
391 totalSize := int64(0)
392 var pHeader pseudoHeader
393 var dec qpackDecoder
394 var hasMethod, hasScheme, hasPath, hasAuthority bool
395 if err := dec.decode(st, func(_ indexType, name, value string) error {
396 totalSize += int64(len(name)) + int64(len(value)) + 32
397 valueCount++
398 if totalSize > sc.maxHeaderBytes {
399 return &streamError{errH3RequestRejected, "headers too large"}
400 }
401
402
403
404
405 if !httpguts.ValidHeaderFieldValue(value) {
406 return &streamError{errH3MessageError, "invalid field value"}
407 }
408 if name == "" || (name[0] == ':' && value == "") {
409
410
411
412 return &streamError{errH3MessageError, "invalid field"}
413 }
414 switch name {
415 case ":method":
416 if hasMethod {
417 return &streamError{errH3MessageError, "duplicate :method"}
418 }
419 hasMethod = true
420 pHeader.method = value
421 case ":scheme":
422 if hasScheme {
423 return &streamError{errH3MessageError, "duplicate :scheme"}
424 }
425 hasScheme = true
426 pHeader.scheme = value
427 case ":path":
428 if hasPath {
429 return &streamError{errH3MessageError, "duplicate :path"}
430 }
431 hasPath = true
432 pHeader.path = value
433 case ":authority":
434 if hasAuthority {
435 return &streamError{errH3MessageError, "duplicate :authority"}
436 }
437 hasAuthority = true
438 pHeader.authority = value
439 default:
440 if !validWireHeaderFieldName(name) {
441 return &streamError{errH3MessageError, "invalid field name"}
442 }
443 header.Add(name, value)
444 }
445 return nil
446 }); err != nil {
447 return nil, pseudoHeader{}, err
448 }
449 if err := st.endFrame(); err != nil {
450 return nil, pseudoHeader{}, err
451 }
452 if hasDisallowedConnectionHeader(header) {
453 return nil, pseudoHeader{}, &streamError{errH3MessageError, "invalid connection-related header"}
454 }
455
456
457
458
459
460
461
462
463
464 if !hasMethod {
465 return nil, pseudoHeader{}, &streamError{errH3MessageError, "missing :method"}
466 }
467 if pHeader.method != "CONNECT" && (!hasScheme || !hasPath) {
468 return nil, pseudoHeader{}, &streamError{errH3MessageError, "missing :scheme or :path for non-CONNECT requests"}
469 }
470 if pHeader.method == "CONNECT" && (hasScheme || hasPath || !hasAuthority) {
471 return nil, pseudoHeader{}, &streamError{
472 errH3MessageError, "CONNECT request must only have :method and :authority pseudo-headers",
473 }
474 }
475 return header, pHeader, nil
476 }
477
478 func (sc *serverConn) sendGoaway() {
479 sc.mu.Lock()
480 if sc.goawaySent || sc.controlStream == nil {
481 sc.mu.Unlock()
482 return
483 }
484 sc.goawaySent = true
485 sc.mu.Unlock()
486
487
488
489 sc.controlStream.writeVarint(int64(frameTypeGoaway))
490 sc.controlStream.writeVarint(int64(sizeVarint(uint64(sc.maxRequestStreamID))))
491 sc.controlStream.writeVarint(sc.maxRequestStreamID)
492 sc.controlStream.Flush()
493 }
494
495
496
497 func (sc *serverConn) requestShouldGoaway(st *stream) bool {
498 sc.mu.Lock()
499 defer sc.mu.Unlock()
500 if sc.goawaySent {
501 return st.stream.ID() >= sc.maxRequestStreamID
502 } else {
503 sc.maxRequestStreamID = max(sc.maxRequestStreamID, st.stream.ID())
504 return false
505 }
506 }
507
508 func (sc *serverConn) handleRequestStream(st *stream) error {
509 if sc.requestShouldGoaway(st) {
510 return &streamError{
511 code: errH3RequestRejected,
512 message: "GOAWAY request with equal or lower ID than the stream has been sent",
513 }
514 }
515
516 readStartTime := time.Now()
517 if t := sc.srv.readHeaderTimeout(); t > 0 {
518 st.readDeadline.set(readStartTime.Add(t))
519 }
520 header, pHeader, err := sc.parseHeader(st)
521 if err != nil {
522 if errors.Is(err, os.ErrDeadlineExceeded) {
523 return &streamError{
524 code: errH3RequestRejected,
525 message: "exceeded deadline while parsing header",
526 }
527 }
528 return err
529 }
530
531 if t := sc.srv.readTimeout(); t > 0 {
532 st.readDeadline.set(readStartTime.Add(t))
533 } else {
534 st.readDeadline.set(time.Time{})
535 }
536 reqInfo := httpcommon.NewServerRequest(httpcommon.ServerRequestParam{
537 Method: pHeader.method,
538 Scheme: pHeader.scheme,
539 Authority: pHeader.authority,
540 Path: pHeader.path,
541 Header: header,
542 })
543 if reqInfo.InvalidReason != "" {
544 return &streamError{
545 code: errH3MessageError,
546 message: reqInfo.InvalidReason,
547 }
548 }
549
550 contentLength := int64(-1)
551 if n, err := strconv.ParseUint(header.Get("Content-Length"), 10, 63); err == nil {
552 contentLength = int64(n)
553 }
554
555 req := (&http.Request{
556 Proto: "HTTP/3.0",
557 Method: pHeader.method,
558 Host: reqInfo.Host,
559 URL: reqInfo.URL,
560 RequestURI: reqInfo.RequestURI,
561 Trailer: reqInfo.Trailer,
562 ProtoMajor: 3,
563 RemoteAddr: sc.qconn.RemoteAddr().String(),
564 Header: header,
565 ContentLength: contentLength,
566 }).WithContext(sc.baseCtx)
567
568 rw := &responseWriter{
569 st: st,
570 headers: make(http.Header),
571 trailer: make(http.Header),
572 bb: make(bodyBuffer, 0, defaultBodyBufferCap),
573 cannotHaveBody: req.Method == "HEAD",
574 bw: &bodyWriter{
575 st: st,
576 remain: -1,
577 flush: false,
578 name: "response",
579 enc: &sc.enc,
580 },
581 }
582
583 if contentLength != 0 || len(reqInfo.Trailer) != 0 {
584 req.Body = &serverRequestReader{
585 rw: rw,
586 br: bodyReader{
587 st: st,
588 remain: contentLength,
589 trailer: reqInfo.Trailer,
590 filterTrailer: true,
591 },
592 needsContinue: reqInfo.NeedsContinue,
593 }
594 defer req.Body.Close()
595 } else {
596 req.Body = http.NoBody
597 }
598
599
600 if t := sc.srv.writeTimeout(); t > 0 {
601 st.writeDeadline.set(time.Now().Add(t))
602 }
603 sc.handler.ServeHTTP(rw, req)
604 return rw.close()
605 }
606
607
608 func (sc *serverConn) abort(err error) {
609 if e, ok := err.(*connectionError); ok {
610 sc.qconn.Abort(&quic.ConnectionCloseError{
611 Code: uint64(e.code),
612 Reason: e.message,
613 })
614 } else {
615 sc.qconn.Abort(err)
616 }
617 }
618
619
620
621 func responseCanHaveBody(status int) bool {
622 switch {
623 case status >= 100 && status <= 199:
624 return false
625 case status == 204:
626 return false
627 case status == 304:
628 return false
629 }
630 return true
631 }
632
633
634
635
636
637 const trailerPrefix = "Trailer:"
638
639 type responseWriter struct {
640 st *stream
641 bw *bodyWriter
642 mu sync.Mutex
643 headers http.Header
644 snapHeaders http.Header
645 trailer http.Header
646 bb bodyBuffer
647 wroteHeader bool
648 statusCode int
649 sent100 bool
650 cannotHaveBody bool
651 bodyLenLeft int64
652 }
653
654 func (rw *responseWriter) Header() http.Header {
655 return rw.headers
656 }
657
658
659
660
661 func (rw *responseWriter) prepareTrailerForWriteLocked() {
662 for name := range rw.trailer {
663 if val, ok := rw.headers[name]; ok {
664 rw.trailer[name] = val
665 } else {
666 delete(rw.trailer, name)
667 }
668 }
669 for name, vals := range rw.headers {
670 if name, found := strings.CutPrefix(name, trailerPrefix); found {
671 name = textproto.CanonicalMIMEHeaderKey(textproto.TrimString(name))
672 rw.trailer[name] = vals
673 }
674 }
675 if len(rw.trailer) > 0 {
676 rw.bw.trailer = rw.trailer
677 }
678 }
679
680
681
682
683
684 func (rw *responseWriter) writeHeaderLockedOnce() {
685 if rw.wroteHeader {
686 return
687 }
688 if !responseCanHaveBody(rw.statusCode) {
689 rw.cannotHaveBody = true
690 }
691
692
693
694 if _, ok := rw.snapHeaders["Trailer"]; ok {
695 extractTrailerFromHeader(rw.snapHeaders, rw.trailer)
696 rw.snapHeaders.Set("Trailer", strings.Join(slices.Sorted(maps.Keys(rw.trailer)), ", "))
697 }
698
699 rw.bb.inferHeader(rw.snapHeaders, rw.statusCode)
700 encHeaders := rw.bw.enc.encode(func(f func(itype indexType, name, value string)) {
701 f(mayIndex, ":status", strconv.Itoa(rw.statusCode))
702 for name, values := range rw.snapHeaders {
703 if !httpguts.ValidHeaderFieldName(name) {
704 continue
705 }
706 for _, val := range values {
707 if !httpguts.ValidHeaderFieldValue(val) {
708 continue
709 }
710
711 f(mayIndex, name, val)
712 }
713 }
714 })
715
716 rw.st.writeVarint(int64(frameTypeHeaders))
717 rw.st.writeVarint(int64(len(encHeaders)))
718 rw.st.Write(encHeaders)
719 rw.wroteHeader = true
720 }
721
722
723
724
725
726 func (rw *responseWriter) writeHeaderLocked(statusCode int) {
727 if rw.wroteHeader {
728 return
729 }
730 if statusCode == 100 {
731 if rw.sent100 {
732 return
733 }
734 rw.sent100 = true
735 }
736 encHeaders := rw.bw.enc.encode(func(f func(itype indexType, name, value string)) {
737 f(mayIndex, ":status", strconv.Itoa(statusCode))
738 for name, values := range rw.headers {
739 if name == "Content-Length" || name == "Transfer-Encoding" {
740 continue
741 }
742 if !httpguts.ValidHeaderFieldName(name) {
743 continue
744 }
745 for _, val := range values {
746 if !httpguts.ValidHeaderFieldValue(val) {
747 continue
748 }
749
750 f(mayIndex, name, val)
751 }
752 }
753 })
754 rw.st.writeVarint(int64(frameTypeHeaders))
755 rw.st.writeVarint(int64(len(encHeaders)))
756 rw.st.Write(encHeaders)
757 }
758
759 func isInfoStatus(status int) bool {
760 return status >= 100 && status < 200
761 }
762
763
764 func checkWriteHeaderCode(code int) {
765
766
767
768
769
770
771
772
773
774
775 if code < 100 || code > 999 {
776 panic(fmt.Sprintf("invalid WriteHeader code %v", code))
777 }
778 }
779
780 func (rw *responseWriter) WriteHeader(statusCode int) {
781
782 rw.mu.Lock()
783 defer rw.mu.Unlock()
784 if rw.statusCode != 0 {
785 return
786 }
787 checkWriteHeaderCode(statusCode)
788
789
790
791 if isInfoStatus(statusCode) {
792 rw.writeHeaderLocked(statusCode)
793 rw.st.Flush()
794 return
795 }
796
797
798
799 if n, err := strconv.ParseUint(rw.headers.Get("Content-Length"), 10, 63); err == nil {
800 rw.bodyLenLeft = int64(n)
801 } else {
802 rw.headers.Del("Content-Length")
803 rw.bodyLenLeft = -1
804 }
805 rw.statusCode = statusCode
806 rw.snapHeaders = rw.headers.Clone()
807 }
808
809
810
811
812
813 func (rw *responseWriter) trimWriteLocked(b []byte) ([]byte, bool) {
814 if rw.bodyLenLeft < 0 {
815 return b, false
816 }
817 n := min(int64(len(b)), rw.bodyLenLeft)
818 rw.bodyLenLeft -= n
819 return b[:n], n != int64(len(b))
820 }
821
822 func (rw *responseWriter) Write(b []byte) (n int, err error) {
823
824
825 rw.WriteHeader(http.StatusOK)
826 rw.mu.Lock()
827 defer rw.mu.Unlock()
828
829 if rw.statusCode == http.StatusNotModified {
830 return 0, http.ErrBodyNotAllowed
831 }
832
833 b, trimmed := rw.trimWriteLocked(b)
834 if trimmed {
835 defer func() {
836 err = http.ErrContentLength
837 }()
838 }
839
840
841
842
843
844
845 initialBLen := len(b)
846 initialBufLen := len(rw.bb)
847 if !rw.wroteHeader || len(b) <= cap(rw.bb)-len(rw.bb) {
848 b = rw.bb.write(b)
849 if len(b) == 0 {
850 return initialBLen, nil
851 }
852 }
853
854
855
856
857
858
859
860 rw.writeHeaderLockedOnce()
861 if rw.cannotHaveBody {
862 return initialBLen, nil
863 }
864 if n, err := rw.bw.write(rw.bb, b); err != nil {
865 return max(0, n-initialBufLen), err
866 }
867 rw.bb.discard()
868 return initialBLen, nil
869 }
870
871 func (rw *responseWriter) SetReadDeadline(deadline time.Time) error {
872 rw.st.readDeadline.set(deadline)
873 return nil
874 }
875
876 func (rw *responseWriter) SetWriteDeadline(deadline time.Time) error {
877 rw.st.writeDeadline.set(deadline)
878 return nil
879 }
880
881 func (rw *responseWriter) EnableFullDuplex() error {
882 return nil
883 }
884
885 func (rw *responseWriter) Flush() { rw.FlushError() }
886 func (rw *responseWriter) FlushError() error {
887
888
889 rw.WriteHeader(http.StatusOK)
890 rw.mu.Lock()
891 defer rw.mu.Unlock()
892 rw.writeHeaderLockedOnce()
893 if !rw.cannotHaveBody {
894 _, err := rw.bw.Write(rw.bb)
895 rw.bb.discard()
896 if err != nil {
897 return err
898 }
899 }
900 return rw.st.Flush()
901 }
902
903 func (rw *responseWriter) close() error {
904 if errors.Is(rw.st.writeDeadline.err(), os.ErrDeadlineExceeded) {
905 return &streamError{
906 code: errH3RequestCancelled,
907 message: "exceeded deadline while writing response",
908 }
909 }
910
911 retErr := rw.FlushError()
912 rw.mu.Lock()
913 defer rw.mu.Unlock()
914 rw.prepareTrailerForWriteLocked()
915 if err := rw.bw.Close(); retErr == nil {
916 retErr = err
917 }
918 if errors.Is(retErr, os.ErrDeadlineExceeded) {
919 return &streamError{
920 code: errH3RequestCancelled,
921 message: retErr.Error(),
922 }
923 }
924 return retErr
925 }
926
927
928
929
930
931 const defaultBodyBufferCap = 512
932
933
934 type bodyBuffer []byte
935
936
937
938 func (bb *bodyBuffer) write(b []byte) []byte {
939 n := min(len(b), cap(*bb)-len(*bb))
940 *bb = append(*bb, b[:n]...)
941 return b[n:]
942 }
943
944
945 func (bb *bodyBuffer) discard() {
946 *bb = (*bb)[:0]
947 }
948
949
950
951
952
953
954 func (bb *bodyBuffer) inferHeader(h http.Header, status int) {
955 if _, ok := h["Date"]; !ok {
956 h.Set("Date", time.Now().UTC().Format(http.TimeFormat))
957 }
958
959
960 hasCE := len(h.Get("Content-Encoding")) > 0
961 _, hasCT := h["Content-Type"]
962 if !hasCE && !hasCT && responseCanHaveBody(status) && len(*bb) > 0 {
963 h.Set("Content-Type", http.DetectContentType(*bb))
964 }
965
966
967
968
969 }
970
971
972
973
974 type serverRequestReader struct {
975 rw *responseWriter
976 br bodyReader
977 needsContinue bool
978 }
979
980
981
982
983
984 func (srr *serverRequestReader) maybeSendContinue() {
985 if !srr.needsContinue {
986 return
987 }
988 srr.rw.mu.Lock()
989 defer srr.rw.mu.Unlock()
990 if srr.rw.sent100 {
991 return
992 }
993 if srr.rw.statusCode != 0 {
994 srr.br.Close()
995 return
996 }
997 srr.rw.writeHeaderLocked(100)
998 srr.rw.st.Flush()
999 }
1000
1001 func (srr *serverRequestReader) Read(p []byte) (int, error) {
1002 srr.maybeSendContinue()
1003 return srr.br.Read(p)
1004 }
1005
1006 func (srr *serverRequestReader) Close() error {
1007 return srr.br.Close()
1008 }
1009
View as plain text