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