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