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