1
2
3
4
5 package http3
6
7 import (
8 "errors"
9 "fmt"
10 "io"
11 "maps"
12 "net/http"
13 "net/netip"
14 "net/url"
15 "os"
16 "reflect"
17 "slices"
18 "strconv"
19 "strings"
20 "sync"
21 "testing"
22 "testing/synctest"
23 "time"
24
25 "golang.org/x/net/quic"
26 )
27
28
29
30
31
32
33
34 func requestHeader(h http.Header) http.Header {
35 minimalHeader := http.Header{
36 ":method": {"GET"},
37 ":scheme": {"https"},
38 ":path": {"/"},
39 }
40 maps.Copy(minimalHeader, h)
41 return minimalHeader
42 }
43
44 func TestServerReceivePushStream(t *testing.T) {
45
46
47
48 synctest.Test(t, func(t *testing.T) {
49 ts := newTestServer(t, nil)
50 tc := ts.connect()
51 tc.newStream(streamTypePush)
52 tc.wantClosed("invalid client-created push stream", errH3StreamCreationError)
53 })
54 }
55
56 func TestServerCancelPushForUnsentPromise(t *testing.T) {
57 synctest.Test(t, func(t *testing.T) {
58 ts := newTestServer(t, nil)
59 tc := ts.connect()
60 tc.greet()
61
62 const pushID = 100
63 tc.control.writeVarint(int64(frameTypeCancelPush))
64 tc.control.writeVarint(int64(sizeVarint(pushID)))
65 tc.control.writeVarint(pushID)
66 tc.control.Flush()
67
68 tc.wantClosed("client canceled never-sent push ID", errH3IDError)
69 })
70 }
71
72 func TestServerHeader(t *testing.T) {
73 synctest.Test(t, func(t *testing.T) {
74 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
75 header := w.Header()
76 for key, values := range r.Header {
77 for _, value := range values {
78 header.Add(key, value)
79 }
80 }
81 w.WriteHeader(204)
82 }))
83 tc := ts.connect()
84 tc.greet()
85
86 reqStream := tc.newStream(streamTypeRequest)
87 reqStream.writeHeaders(requestHeader(http.Header{
88 "header-from-client": {"that", "should", "be", "echoed"},
89 }))
90 reqStream.wantSomeHeaders(http.Header{
91 ":status": {"204"},
92 "Header-From-Client": {"that", "should", "be", "echoed"},
93 })
94 reqStream.wantClosed("request is complete")
95 })
96 }
97
98 func TestServerHeaderSnapshot(t *testing.T) {
99 synctest.Test(t, func(t *testing.T) {
100 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
101 w.Header().Set("X-Test-Header", "original")
102 w.WriteHeader(200)
103 w.Header().Set("X-Test-Header", "modified")
104 w.Write([]byte("body"))
105 }))
106 tc := ts.connect()
107 tc.greet()
108
109 reqStream := tc.newStream(streamTypeRequest)
110 reqStream.writeHeaders(requestHeader(nil))
111 reqStream.wantSomeHeaders(http.Header{
112 ":status": {"200"},
113 "X-Test-Header": {"original"},
114 })
115 reqStream.wantData([]byte("body"))
116 reqStream.wantClosed("request is complete")
117 })
118 }
119
120 func TestServerHeaderInvalid(t *testing.T) {
121 tests := []struct {
122 name string
123 header http.Header
124 wantError bool
125 }{
126 {
127 name: "header name with control character",
128 header: http.Header{"name\nevilinjection": {"Value"}},
129 wantError: true,
130 },
131 {
132 name: "header name with uppercase character",
133 header: http.Header{"nAme": {"Value"}},
134 wantError: true,
135 },
136 {
137 name: "pseudo-header name with control character",
138 header: http.Header{":path\nevilinjection": {"Value"}},
139 wantError: true,
140 },
141 {
142 name: "pseudo-header name with uppercase character",
143 header: http.Header{":meThod": {"Value"}},
144 wantError: true,
145 },
146 {
147 name: "header value with control character",
148 header: http.Header{"name": {"Value\nEvilInjection"}},
149 wantError: true,
150 },
151 {
152 name: "pseudo-header value with control character",
153 header: http.Header{":method": {"Value\nEvilInjection"}},
154 wantError: true,
155 },
156 {
157 name: "connection header name",
158 header: http.Header{"connection": {"foo"}},
159 wantError: true,
160 },
161 {
162 name: "keep-alive header name",
163 header: http.Header{"Keep-Alive": {"foo"}},
164 wantError: true,
165 },
166 {
167 name: "proxy-connection header name",
168 header: http.Header{"proxy-connection": {"foo"}},
169 wantError: true,
170 },
171 {
172 name: "transfer-encoding header name",
173 header: http.Header{"transfer-encoding": {"foo"}},
174 wantError: true,
175 },
176 {
177 name: "upgrade header name",
178 header: http.Header{"upgrade": {"foo"}},
179 wantError: true,
180 },
181 {
182 name: "te header name",
183 header: http.Header{"te": {"foo"}},
184 wantError: true,
185 },
186 {
187 name: "te header name with trailers value",
188 header: http.Header{"te": {"trailers"}},
189 wantError: false,
190 },
191 }
192 for _, tt := range tests {
193 synctestSubtest(t, tt.name, func(t *testing.T) {
194 body := []byte("some data")
195 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
196 w.Write(body)
197 }))
198 tc := ts.connect()
199 tc.greet()
200
201 reqStream := tc.newStream(streamTypeRequest)
202 reqStream.writeHeadersRaw(requestHeader(tt.header))
203
204 if tt.wantError {
205 reqStream.wantError(quic.StreamError(errH3MessageError))
206 } else {
207 reqStream.wantHeaders(nil)
208 reqStream.wantData(body)
209 reqStream.wantClosed("request is complete")
210 }
211 })
212 }
213 }
214
215 func TestServerPseudoHeader(t *testing.T) {
216 synctest.Test(t, func(t *testing.T) {
217 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
218
219
220 if len(r.Header) != 0 {
221 t.Errorf("got %v, want request header to be empty", r.Header)
222 }
223 if r.Method != "GET" {
224 t.Errorf("got %v, want GET method", r.Method)
225 }
226 if r.Host != "fake.tld:1234" {
227 t.Errorf("got %v, want fake.tld:1234", r.Host)
228 }
229 wantURL := &url.URL{
230 Path: "/some/path",
231 RawQuery: "query=value&query2=value2#fragment",
232 }
233 if !reflect.DeepEqual(r.URL, wantURL) {
234 t.Errorf("got %v, want URL to be %v", r.URL, wantURL)
235 }
236
237
238
239 header := w.Header()
240 header.Add(":status", "123")
241 w.WriteHeader(321)
242 }))
243 tc := ts.connect()
244 tc.greet()
245
246 reqStream := tc.newStream(streamTypeRequest)
247 reqStream.writeHeaders(http.Header{
248 ":method": {"GET"},
249 ":authority": {"fake.tld:1234"},
250 ":scheme": {"https"},
251 ":path": {"/some/path?query=value&query2=value2#fragment"},
252 })
253 reqStream.wantSomeHeaders(http.Header{":status": {"321"}})
254 reqStream.wantClosed("request is complete")
255
256 reqStream = tc.newStream(streamTypeRequest)
257 reqStream.writeHeaders(http.Header{})
258 reqStream.wantError(quic.StreamError(errH3MessageError))
259 })
260 }
261
262 func TestServerPseudoHeaderCount(t *testing.T) {
263 tests := []struct {
264 name string
265 header http.Header
266 wantError bool
267 }{
268 {
269 name: "missing method pseudo-header",
270 header: http.Header{
271 ":scheme": {"https"},
272 ":path": {"/"},
273 ":authority": {"fake.tld:1234"},
274 },
275 wantError: true,
276 },
277 {
278 name: "valid pseudo-headers for non-CONNECT request",
279 header: http.Header{
280 ":method": {"GET"},
281 ":scheme": {"https"},
282 ":path": {"/"},
283 },
284 wantError: false,
285 },
286 {
287 name: "extraneous pseudo-headers for non-CONNECT request",
288 header: http.Header{
289 ":method": {"GET", "GET"},
290 ":scheme": {"https"},
291 ":path": {"/"},
292 },
293 wantError: true,
294 },
295 {
296 name: "missing pseudo-headers for non-CONNECT request",
297 header: http.Header{
298 ":method": {"GET", "GET"},
299 ":path": {"/"},
300 },
301 wantError: true,
302 },
303 {
304 name: "valid pseudo-headers for CONNECT request",
305 header: http.Header{
306 ":method": {"CONNECT"},
307 ":authority": {"fake.tld:1234"},
308 },
309 wantError: false,
310 },
311 {
312 name: "extraneous pseudo-headers for CONNECT request",
313 header: http.Header{
314 ":method": {"CONNECT"},
315 ":authority": {"fake.tld:1234"},
316 ":path": {"/"},
317 },
318 wantError: true,
319 },
320 {
321 name: "missing pseudo-headers for CONNECT request",
322 header: http.Header{
323 ":method": {"CONNECT"},
324 },
325 wantError: true,
326 },
327 }
328 for _, tt := range tests {
329 synctestSubtest(t, tt.name, func(t *testing.T) {
330 body := []byte("some data")
331 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
332 w.Write(body)
333 }))
334 tc := ts.connect()
335 tc.greet()
336
337 reqStream := tc.newStream(streamTypeRequest)
338 reqStream.writeHeaders(tt.header)
339
340 if tt.wantError {
341 reqStream.wantError(quic.StreamError(errH3MessageError))
342 } else {
343 reqStream.wantHeaders(nil)
344 reqStream.wantData(body)
345 reqStream.wantClosed("request is complete")
346 }
347 })
348 }
349 }
350
351 func TestServerInvalidHeader(t *testing.T) {
352 synctest.Test(t, func(t *testing.T) {
353 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
354 w.Header().Add("valid-name", "valid value")
355
356 w.Header().Add("invalid name with spaces", "some value")
357 w.Header().Add("some-name", "invalid value with \n")
358 w.Header().Add("valid-name-2", "valid value 2")
359 w.WriteHeader(200)
360 }))
361 tc := ts.connect()
362 tc.greet()
363
364 reqStream := tc.newStream(streamTypeRequest)
365 reqStream.writeHeaders(requestHeader(nil))
366 reqStream.wantSomeHeaders(http.Header{
367 ":status": {"200"},
368 "Valid-Name": {"valid value"},
369 "Valid-Name-2": {"valid value 2"},
370 })
371 reqStream.wantClosed("request is complete")
372 })
373 }
374
375 func TestServerAuthorityAndHostHeader(t *testing.T) {
376 for _, test := range []struct {
377 name string
378 h http.Header
379 valid bool
380 wantHost string
381 }{{
382 name: "authority host mismatch",
383 h: http.Header{
384 ":authority": {"example.tld"},
385 "host": {"other.tld"},
386 },
387 }, {
388
389
390
391 name: "authority host case differs",
392 h: http.Header{
393 ":authority": {"example.tld"},
394 "host": {"EXAMPLE.TLD"},
395 },
396 }, {
397 name: "authority and multiple host",
398 h: http.Header{
399 ":authority": {"example.tld"},
400 "host": {"example.tld", "example.tld"},
401 },
402 }, {
403 name: "multiple host only",
404 h: http.Header{
405 "host": {"example.tld", "example.tld"},
406 },
407 }, {
408 name: "multiple authority only",
409 h: http.Header{
410 ":authority": {"example.tld", "example.tld"},
411 },
412 }, {
413 name: "empty authority",
414 h: http.Header{
415 ":authority": {""},
416 },
417 }, {
418 name: "invalid authority",
419 h: http.Header{
420 ":authority": {"example . tld"},
421 },
422 }, {
423 name: "invalid host",
424 h: http.Header{
425 "host": {"example . tld"},
426 },
427 }, {
428 name: "authority only",
429 h: http.Header{
430 ":authority": {"example.tld"},
431 },
432 valid: true,
433 wantHost: "example.tld",
434 }, {
435 name: "host only",
436 h: http.Header{
437 "host": {"example.tld"},
438 },
439 valid: true,
440 wantHost: "example.tld",
441 }, {
442 name: "authority host match",
443 h: http.Header{
444 ":authority": {"example.tld"},
445 "host": {"example.tld"},
446 },
447 valid: true,
448 wantHost: "example.tld",
449 }, {
450 name: "authority host match with port",
451 h: http.Header{
452 ":authority": {"example.tld:443"},
453 "host": {"example.tld:443"},
454 },
455 valid: true,
456 wantHost: "example.tld:443",
457 }, {
458 name: "authority host mismatch with port",
459 h: http.Header{
460 ":authority": {"example.tld:80"},
461 "host": {"example.tld:443"},
462 },
463 }, {
464 name: "userinfo in authority",
465 h: http.Header{
466 ":authority": {"user:pass@example.tld"},
467 },
468 }, {
469 name: "userinfo in host",
470 h: http.Header{
471 "host": {"user:pass@example.tld"},
472 },
473 }, {
474 name: "neither authority nor host",
475 h: http.Header{},
476 valid: true,
477 wantHost: "",
478 }} {
479 synctestSubtest(t, test.name, func(t *testing.T) {
480 ts := newTestServer(t, nil)
481 tc := ts.connect()
482 tc.greet()
483
484 reqStream := tc.newStream(streamTypeRequest)
485 reqStream.writeHeaders(requestHeader(test.h))
486 if test.valid {
487 call := tc.nextHandlerCall()
488 if call == nil {
489 t.Fatal("no server handler call; want one")
490 }
491 if got, want := call.req.Host, test.wantHost; got != want {
492 t.Errorf("handler got Host %q, want %q", got, want)
493 }
494 if h, ok := call.req.Header["Host"]; ok {
495 t.Errorf(`handler got Header["Host"] = %q, want unset`, h)
496 }
497 } else {
498 reqStream.wantError(quic.StreamError(errH3MessageError))
499 }
500 })
501 }
502 }
503
504 func TestServerInvalidStatus(t *testing.T) {
505 synctest.Test(t, func(t *testing.T) {
506 gotpanic := make(chan bool)
507 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
508 defer close(gotpanic)
509 defer func() {
510 if e := recover(); e != nil {
511 got := fmt.Sprintf("%T, %v", e, e)
512 want := "string, invalid WriteHeader code 0"
513 if got != want {
514 t.Errorf("unexpected panic value:\n got: %v\nwant: %v\n", got, want)
515 }
516 gotpanic <- true
517
518
519
520 w.WriteHeader(503)
521
522
523
524 w.WriteHeader(0)
525 }
526 }()
527 w.WriteHeader(0)
528 }))
529 tc := ts.connect()
530 tc.greet()
531
532 reqStream := tc.newStream(streamTypeRequest)
533 reqStream.writeHeaders(requestHeader(nil))
534 if !<-gotpanic {
535 t.Error("expected panic in handler")
536 }
537 synctest.Wait()
538 reqStream.wantSomeHeaders(http.Header{
539 ":status": {"503"},
540 })
541 reqStream.wantClosed("request is complete")
542 })
543 }
544
545 func TestServerHeaderLimits(t *testing.T) {
546 for _, test := range []struct {
547 name string
548 header http.Header
549 trailer http.Header
550 valid bool
551 maxHeaderBytes int
552 maxHeaderValueCount int
553 }{{
554 name: "within limits",
555 header: {
556 "x-foo": {strings.Repeat("x", 1000)},
557 },
558 maxHeaderBytes: 1500,
559 valid: true,
560 }, {
561 name: "too many header bytes",
562 header: {
563 "x-foo": {strings.Repeat("x", 1000)},
564 "x-bar": {strings.Repeat("x", 1000)},
565 },
566 maxHeaderBytes: 1500,
567 }, {
568 name: "sent trailer within limits",
569 header: {
570 "trailer": {"x-foo"},
571 },
572 trailer: http.Header{
573 "x-foo": {strings.Repeat("x", 1000)},
574 },
575 maxHeaderBytes: 1500,
576 valid: true,
577 }, {
578 name: "too many sent trailer bytes",
579 header: {
580 "trailer": {"x-foo, x-bar"},
581 },
582 trailer: http.Header{
583 "x-foo": {strings.Repeat("x", 1000)},
584 "x-bar": {strings.Repeat("x", 1000)},
585 },
586 maxHeaderBytes: 1500,
587 }, {
588 name: "field count within limit",
589 header: {
590
591 "x-foo": {"4"},
592 "x-bar": {"5"},
593 },
594 maxHeaderBytes: 1500,
595 maxHeaderValueCount: 5,
596 valid: true,
597 }, {
598 name: "field count over limit",
599 header: {
600
601 "x-foo": {"4"},
602 "x-bar": {"5"},
603 },
604 maxHeaderBytes: 1500,
605 maxHeaderValueCount: 4,
606 }, {
607 name: "declared trailer field count within limit",
608 header: {
609 "trailer": {"a, b, c, d, e"},
610 },
611 maxHeaderBytes: 1500,
612 maxHeaderValueCount: 5,
613 valid: true,
614 }, {
615 name: "declared trailer field count over limit",
616 header: {
617 "trailer": {"a, b, c, d, e"},
618 },
619 maxHeaderBytes: 1500,
620 maxHeaderValueCount: 4,
621 }, {
622 name: "declared trailer bytes over limit",
623 header: {
624 "trailer": {strings.Repeat("a,", 50)},
625 },
626 maxHeaderBytes: 1500,
627 }} {
628 synctestSubtest(t, test.name, func(t *testing.T) {
629 ts := newTestServer(t, nil)
630 ts.s.srv1.MaxHeaderBytes = test.maxHeaderBytes
631 ts.s.srv1.MaxHeaderValueCount = test.maxHeaderValueCount
632 tc := ts.connect()
633 tc.greet()
634
635 reqStream := tc.newStream(streamTypeRequest)
636 reqStream.writeHeaders(requestHeader(test.header))
637
638 if test.trailer == nil && !test.valid {
639 reqStream.wantSomeHeaders(http.Header{
640 ":status": {"431"},
641 })
642 reqStream.wantClosed("request is complete")
643 return
644 }
645
646 call := tc.nextHandlerCall()
647 if call == nil {
648 t.Fatal("no server handler call; want one")
649 }
650 if test.trailer == nil {
651 return
652 }
653
654 reqStream.writeHeaders(test.trailer)
655 _, err := io.ReadAll(call.req.Body)
656 if (err == nil) != test.valid {
657 t.Fatalf("io.ReadAll(req.Body) = %v, want valid=%v", err, test.valid)
658 }
659 })
660 }
661 }
662
663 func TestServerBody(t *testing.T) {
664 synctest.Test(t, func(t *testing.T) {
665 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
666 body, err := io.ReadAll(r.Body)
667 if err != nil {
668 t.Fatal(err)
669 }
670 w.Write([]byte(r.URL.Path))
671 w.Write(body)
672 }))
673 tc := ts.connect()
674 tc.greet()
675
676 reqStream := tc.newStream(streamTypeRequest)
677 reqStream.writeHeaders(requestHeader(nil))
678 bodyContent := []byte("some body content that should be echoed")
679 reqStream.writeData(bodyContent)
680 reqStream.CloseWrite()
681 reqStream.wantSomeHeaders(http.Header{":status": {"200"}})
682
683 reqStream.wantData(append([]byte("/"), bodyContent...))
684 reqStream.wantClosed("request is complete")
685 })
686 }
687
688 func TestServerHeadResponseNoBody(t *testing.T) {
689 bodyContent := []byte("response body that will not be sent for HEAD requests")
690 synctest.Test(t, func(t *testing.T) {
691 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
692 w.Write(bodyContent)
693 }))
694 tc := ts.connect()
695 tc.greet()
696
697 reqStream := tc.newStream(streamTypeRequest)
698 reqStream.writeHeaders(requestHeader(nil))
699 reqStream.wantSomeHeaders(http.Header{":status": {"200"}})
700 reqStream.wantData(bodyContent)
701 reqStream.wantClosed("request is complete")
702
703 reqStream = tc.newStream(streamTypeRequest)
704 reqStream.writeHeaders(requestHeader(http.Header{":method": {http.MethodHead}}))
705 reqStream.wantSomeHeaders(http.Header{":status": {"200"}})
706 reqStream.wantClosed("request is complete")
707 })
708 }
709
710 func TestServerShutdownGoaway(t *testing.T) {
711 synctest.Test(t, func(t *testing.T) {
712 ts := newTestServer(t, nil)
713
714 tc := ts.connect()
715 tc.greet()
716 tc.wantNotClosed("after initial connection handshake")
717
718 requestCount := int64(5)
719 for range requestCount {
720 tc.newStream(streamTypeRequest).writeHeaders(requestHeader(nil))
721 }
722
723 control := tc.wantStream(streamTypeControl)
724 control.wantSettings(nil)
725
726 shutdownComplete := make(chan any)
727 go func() {
728 ts.s.shutdown(t.Context())
729 shutdownComplete <- struct{}{}
730 }()
731 control.wantGoaway((requestCount - 1) * 4)
732 <-shutdownComplete
733 })
734 }
735
736 func TestServerHandlerEmpty(t *testing.T) {
737 synctest.Test(t, func(t *testing.T) {
738 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
739
740 }))
741 tc := ts.connect()
742 tc.greet()
743
744 reqStream := tc.newStream(streamTypeRequest)
745 reqStream.writeHeaders(requestHeader(nil))
746 reqStream.wantSomeHeaders(http.Header{":status": {"200"}})
747 reqStream.wantClosed("request is complete")
748 })
749 }
750
751 func TestServerHandlerFlushing(t *testing.T) {
752 synctest.Test(t, func(t *testing.T) {
753 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
754 time.Sleep(time.Second)
755 w.Write([]byte("first"))
756
757 time.Sleep(time.Second)
758 w.Write([]byte("second"))
759 w.(http.Flusher).Flush()
760
761 time.Sleep(time.Second)
762 w.Write([]byte("third"))
763 }))
764 tc := ts.connect()
765 tc.greet()
766
767 reqStream := tc.newStream(streamTypeRequest)
768 reqStream.writeHeaders(requestHeader(nil))
769 respBody := make([]byte, 100)
770
771 time.Sleep(time.Second)
772 synctest.Wait()
773 if n, err := reqStream.Read(respBody); err == nil {
774 t.Errorf("got %v bytes read, want no message yet", n)
775 }
776
777 time.Sleep(time.Second)
778 synctest.Wait()
779 if _, err := reqStream.Read(respBody); err != nil {
780 t.Errorf("failed to read partial response from server, got err: %v", err)
781 }
782
783 time.Sleep(time.Second)
784 synctest.Wait()
785 if _, err := reqStream.Read(respBody); err != io.EOF {
786 t.Errorf("got err %v, want EOF", err)
787 }
788 reqStream.wantClosed("request is complete")
789 })
790 }
791
792 func TestServerHandlerStreaming(t *testing.T) {
793 synctest.Test(t, func(t *testing.T) {
794 stream := make(chan string)
795 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
796
797
798 w.(http.Flusher).Flush()
799 for str := range stream {
800 w.Write([]byte(str))
801 w.(http.Flusher).Flush()
802 }
803 }))
804 tc := ts.connect()
805 tc.greet()
806
807 reqStream := tc.newStream(streamTypeRequest)
808 reqStream.writeHeaders(requestHeader(nil))
809 reqStream.wantSomeHeaders(http.Header{":status": {"200"}})
810
811 for _, data := range []string{"a", "bunch", "of", "things", "to", "stream"} {
812 stream <- data
813 reqStream.wantData([]byte(data))
814 }
815 close(stream)
816 reqStream.wantClosed("request is complete")
817 })
818 }
819
820 func TestServerHandlerDeclaresContentLength(t *testing.T) {
821 tests := []struct {
822 name string
823 contentLen string
824 actualContentLen int
825 wantWrittenLen int
826 wantTrimmed bool
827 wantCLHeader bool
828 }{
829 {
830 name: "accurate content length",
831 contentLen: "100",
832 actualContentLen: 100,
833 wantWrittenLen: 100,
834 wantCLHeader: true,
835 },
836 {
837 name: "larger content length",
838 contentLen: "100",
839 actualContentLen: 10,
840 wantWrittenLen: 10,
841 wantCLHeader: true,
842 },
843 {
844 name: "smaller content length",
845 contentLen: "10",
846 actualContentLen: 100,
847 wantWrittenLen: 10,
848 wantTrimmed: true,
849 wantCLHeader: true,
850 },
851 {
852 name: "non-numeric string",
853 contentLen: "intentional gibberish",
854 actualContentLen: 100,
855 wantWrittenLen: 100,
856 },
857 {
858 name: "negative number",
859 contentLen: "-10",
860 actualContentLen: 100,
861 wantWrittenLen: 100,
862 },
863 {
864 name: "plus sign",
865 contentLen: "+10",
866 actualContentLen: 100,
867 wantWrittenLen: 100,
868 },
869 {
870 name: "empty",
871 contentLen: "",
872 actualContentLen: 100,
873 wantWrittenLen: 100,
874 },
875 {
876 name: "large valid content length",
877 contentLen: "3000000000",
878 actualContentLen: 100,
879 wantWrittenLen: 100,
880 wantCLHeader: true,
881 },
882 {
883 name: "content length overflowing int64",
884 contentLen: "9223372036854775808",
885 actualContentLen: 100,
886 wantWrittenLen: 100,
887 },
888 }
889
890 for _, tt := range tests {
891 synctestSubtest(t, tt.name, func(t *testing.T) {
892 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
893 w.Header().Set("Content-Length", tt.contentLen)
894 var written int
895 var lastErr error
896 for range tt.actualContentLen {
897 n, err := w.Write([]byte("a"))
898 written += n
899 lastErr = err
900 }
901 if tt.wantTrimmed != (lastErr != nil) {
902 t.Errorf("got %v error when writing response body, even though wantTrimmed is %v", lastErr, tt.wantTrimmed)
903 }
904 if written != tt.wantWrittenLen {
905 t.Errorf("got %v bytes written by the server, want %v bytes", written, tt.wantWrittenLen)
906 }
907 }))
908 tc := ts.connect()
909 tc.greet()
910
911 reqStream := tc.newStream(streamTypeRequest)
912 reqStream.writeHeaders(requestHeader(nil))
913 expectedHeaders := http.Header{
914 ":status": {"200"},
915 "Content-Type": {"text/plain; charset=utf-8"},
916 "Date": {"Sat, 01 Jan 2000 00:00:00 GMT"},
917 }
918 if tt.wantCLHeader {
919 expectedHeaders.Set("Content-Length", tt.contentLen)
920 }
921 reqStream.wantHeaders(expectedHeaders)
922 reqStream.wantData(slices.Repeat([]byte("a"), tt.wantWrittenLen))
923 reqStream.wantClosed("request is complete")
924 })
925 }
926 }
927
928 func TestServerExpect100Continue(t *testing.T) {
929 synctest.Test(t, func(t *testing.T) {
930 streamIdle := make(chan bool)
931 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
932
933
934 if len(r.Header) > 0 {
935 t.Errorf("got %v, want request header to be empty", r.Header)
936 }
937
938 <-streamIdle
939 body, err := io.ReadAll(r.Body)
940 if err != nil {
941 t.Fatal(err)
942 }
943
944
945 w.Write(body)
946 }))
947 tc := ts.connect()
948 tc.greet()
949
950
951 reqStream := tc.newStream(streamTypeRequest)
952 reqStream.writeHeaders(requestHeader(http.Header{
953 "expect": {"100-continue"},
954 }))
955
956 reqStream.wantIdle("stream is idle until server sends an HTTP 100 status")
957 streamIdle <- true
958
959
960 reqStream.wantSomeHeaders(http.Header{":status": {"100"}})
961 body := []byte("body that will be echoed back if we get status 100")
962 reqStream.writeData(body)
963 reqStream.CloseWrite()
964
965
966 reqStream.wantSomeHeaders(http.Header{":status": {"200"}})
967 reqStream.wantData(body)
968 reqStream.wantClosed("request is complete")
969 })
970 }
971
972 func TestServerExpect100ContinueSentManually(t *testing.T) {
973 synctest.Test(t, func(t *testing.T) {
974 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
975 w.WriteHeader(100)
976 body, err := io.ReadAll(r.Body)
977 if err != nil {
978 t.Fatal(err)
979 }
980 w.Write(body)
981 }))
982 tc := ts.connect()
983 tc.greet()
984
985
986 reqStream := tc.newStream(streamTypeRequest)
987 reqStream.writeHeaders(requestHeader(http.Header{
988 "expect": {"100-continue"},
989 }))
990
991
992 reqStream.wantSomeHeaders(http.Header{":status": {"100"}})
993 body := []byte("body that will be echoed back")
994 reqStream.writeData(body)
995 reqStream.CloseWrite()
996
997
998 reqStream.wantSomeHeaders(http.Header{":status": {"200"}})
999 reqStream.wantData(body)
1000 reqStream.wantClosed("request is complete")
1001 })
1002 }
1003
1004 func TestServerExpect100ContinueRejected(t *testing.T) {
1005 synctest.Test(t, func(t *testing.T) {
1006 rejectBody := []byte("not allowed")
1007 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1008 w.WriteHeader(403)
1009 w.Write(rejectBody)
1010 }))
1011 tc := ts.connect()
1012 tc.greet()
1013
1014
1015 reqStream := tc.newStream(streamTypeRequest)
1016 reqStream.writeHeaders(requestHeader(http.Header{
1017 "expect": {"100-continue"},
1018 }))
1019
1020
1021 reqStream.wantSomeHeaders(http.Header{":status": {"403"}})
1022 reqStream.wantData(rejectBody)
1023 reqStream.wantClosed("request is complete")
1024 })
1025 }
1026
1027 func TestServer100ContinueBodyReadAfterFinalResponse(t *testing.T) {
1028 synctest.Test(t, func(t *testing.T) {
1029 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1030 w.WriteHeader(200)
1031 w.(http.Flusher).Flush()
1032
1033
1034
1035 if _, err := io.ReadAll(r.Body); err == nil {
1036 t.Errorf("got %v, want an error", err)
1037 }
1038 }))
1039 tc := ts.connect()
1040 tc.greet()
1041
1042
1043 reqStream := tc.newStream(streamTypeRequest)
1044 reqStream.writeHeaders(requestHeader(http.Header{
1045 "expect": {"100-continue"},
1046 }))
1047
1048
1049 reqStream.wantSomeHeaders(http.Header{":status": {"200"}})
1050 reqStream.wantClosed("request is complete")
1051 })
1052 }
1053
1054 func TestServer100ContinueBodyReadAfter100AndFinalResponse(t *testing.T) {
1055 synctest.Test(t, func(t *testing.T) {
1056 body := []byte("client body")
1057 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1058 w.WriteHeader(100)
1059 w.WriteHeader(200)
1060 w.(http.Flusher).Flush()
1061
1062 if gotBody, err := io.ReadAll(r.Body); err != nil || string(gotBody) != string(body) {
1063 t.Errorf("io.ReadAll(r.Body) = %v, %v; want %v, nil", gotBody, err, body)
1064 }
1065 }))
1066 tc := ts.connect()
1067 tc.greet()
1068
1069
1070 reqStream := tc.newStream(streamTypeRequest)
1071 reqStream.writeHeaders(requestHeader(http.Header{
1072 "expect": {"100-continue"},
1073 }))
1074
1075
1076 reqStream.wantSomeHeaders(http.Header{":status": {"100"}})
1077 reqStream.writeData(body)
1078 reqStream.CloseWrite()
1079 reqStream.wantSomeHeaders(http.Header{":status": {"200"}})
1080 reqStream.wantClosed("request is complete")
1081 })
1082 }
1083
1084 func TestServerHandlerReadReqWithNoBody(t *testing.T) {
1085 synctest.Test(t, func(t *testing.T) {
1086 serverBody := []byte("hello from server!")
1087 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1088 if _, err := io.ReadAll(r.Body); err != nil {
1089 t.Errorf("got %v err when reading from an empty request body, want nil", err)
1090 }
1091 w.Write(serverBody)
1092 }))
1093 tc := ts.connect()
1094 tc.greet()
1095
1096
1097
1098 reqStream := tc.newStream(streamTypeRequest)
1099 reqStream.writeHeaders(requestHeader(nil))
1100 reqStream.CloseWrite()
1101 reqStream.wantSomeHeaders(http.Header{":status": {"200"}})
1102 reqStream.wantData(serverBody)
1103 reqStream.wantClosed("request is complete")
1104
1105
1106
1107 reqStream = tc.newStream(streamTypeRequest)
1108 reqStream.writeHeaders(requestHeader(http.Header{
1109 "content-length": {"0"},
1110 }))
1111 reqStream.wantSomeHeaders(http.Header{":status": {"200"}})
1112 reqStream.wantData(serverBody)
1113 reqStream.wantClosed("request is complete")
1114 })
1115 }
1116
1117 func TestServerHandlerReadTrailer(t *testing.T) {
1118 synctest.Test(t, func(t *testing.T) {
1119 body := []byte("some body")
1120 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1121 wantTrailer := http.Header{
1122 "Client-Trailer-A": nil,
1123 "Client-Trailer-B": nil,
1124 }
1125 if !reflect.DeepEqual(r.Trailer, wantTrailer) {
1126 t.Errorf("got %v; want trailer to be %v before reading the body", r.Trailer, wantTrailer)
1127 }
1128 if _, err := io.ReadAll(r.Body); err != nil {
1129 t.Fatal(err)
1130 }
1131 wantTrailer = http.Header{
1132 "Client-Trailer-A": {"valuea"},
1133 "Client-Trailer-B": {"valueb"},
1134 }
1135 if !reflect.DeepEqual(r.Trailer, wantTrailer) {
1136 t.Errorf("got %v; want trailer to be %v after reading the body", r.Trailer, wantTrailer)
1137 }
1138 w.WriteHeader(200)
1139 }))
1140 tc := ts.connect()
1141 tc.greet()
1142
1143 reqStream := tc.newStream(streamTypeRequest)
1144 reqStream.writeHeaders(requestHeader(http.Header{
1145 "trailer": {"Client-Trailer-A, Client-Trailer-B"},
1146 }))
1147 reqStream.writeData(body)
1148 reqStream.writeHeaders(http.Header{
1149 "Client-Trailer-A": {"valuea"},
1150 "Client-Trailer-B": {"valueb"},
1151
1152 "Undeclared-Trailer": {"undeclared"},
1153 })
1154 reqStream.wantHeaders(nil)
1155 reqStream.wantClosed("request is complete")
1156 })
1157 }
1158
1159 func TestServerHandlerReadTrailerNoBody(t *testing.T) {
1160 synctest.Test(t, func(t *testing.T) {
1161 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1162 wantTrailer := http.Header{
1163 "Client-Trailer-A": nil,
1164 "Client-Trailer-B": nil,
1165 }
1166 if !reflect.DeepEqual(r.Trailer, wantTrailer) {
1167 t.Errorf("got %v; want trailer to be %v before reading the body", r.Trailer, wantTrailer)
1168 }
1169 if _, err := io.ReadAll(r.Body); err != nil {
1170 t.Fatal(err)
1171 }
1172 wantTrailer = http.Header{
1173 "Client-Trailer-A": {"valuea"},
1174 "Client-Trailer-B": {"valueb"},
1175 }
1176 if !reflect.DeepEqual(r.Trailer, wantTrailer) {
1177 t.Errorf("got %v; want trailer to be %v after reading the body", r.Trailer, wantTrailer)
1178 }
1179 w.WriteHeader(200)
1180 }))
1181 tc := ts.connect()
1182 tc.greet()
1183
1184 reqStream := tc.newStream(streamTypeRequest)
1185 reqStream.writeHeaders(requestHeader(http.Header{
1186 "trailer": {"Client-Trailer-A, Client-Trailer-B"},
1187 "content-length": {"0"},
1188 }))
1189 reqStream.writeHeaders(http.Header{
1190 "Client-Trailer-A": {"valuea"},
1191 "Client-Trailer-B": {"valueb"},
1192
1193 "Undeclared-Trailer": {"undeclared"},
1194 })
1195 reqStream.wantHeaders(nil)
1196 reqStream.wantClosed("request is complete")
1197 })
1198 }
1199
1200 func TestServerHandlerWriteTrailer(t *testing.T) {
1201 synctest.Test(t, func(t *testing.T) {
1202 body := []byte("some body")
1203 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1204 w.Header().Set("Trailer", "server-trailer-a, server-trailer-b")
1205 w.Header().Add("Trailer", "Server-Trailer-C")
1206
1207 w.Write(body)
1208
1209 w.Header().Set("server-trailer-a", "valuea")
1210 w.Header().Set("Server-Trailer-C", "valuec")
1211
1212
1213 w.Header().Set("Server-Trailer-Not-Declared", "should be omitted")
1214 w.Header().Set("Trailer:Undeclared-Trailer-Exception", "should be sent")
1215 }))
1216 tc := ts.connect()
1217 tc.greet()
1218
1219 reqStream := tc.newStream(streamTypeRequest)
1220 reqStream.writeHeaders(requestHeader(nil))
1221 reqStream.wantSomeHeaders(http.Header{
1222 ":status": {"200"},
1223 "Trailer": {"Server-Trailer-A, Server-Trailer-B, Server-Trailer-C"},
1224 })
1225 reqStream.wantData(body)
1226 reqStream.wantSomeHeaders(http.Header{
1227 "Server-Trailer-A": {"valuea"},
1228 "Server-Trailer-C": {"valuec"},
1229 "Undeclared-Trailer-Exception": {"should be sent"},
1230 })
1231 reqStream.wantClosed("request is complete")
1232 })
1233 }
1234
1235 func TestServerHandlerWriteTrailerNoBody(t *testing.T) {
1236 synctest.Test(t, func(t *testing.T) {
1237 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1238 w.Header().Set("Trailer", "server-trailer-a, server-trailer-b")
1239 w.Header().Add("Trailer", "Server-Trailer-C")
1240
1241 w.(http.Flusher).Flush()
1242
1243 w.Header().Set("server-trailer-a", "valuea")
1244 w.Header().Set("Server-Trailer-C", "valuec")
1245
1246
1247 w.Header().Set("Server-Trailer-Not-Declared", "should be omitted")
1248 w.Header().Set("Trailer:undeclared-trailer-exception", "should be sent")
1249 }))
1250 tc := ts.connect()
1251 tc.greet()
1252
1253 reqStream := tc.newStream(streamTypeRequest)
1254 reqStream.writeHeaders(requestHeader(nil))
1255 reqStream.wantSomeHeaders(http.Header{
1256 ":status": {"200"},
1257 "Trailer": {"Server-Trailer-A, Server-Trailer-B, Server-Trailer-C"},
1258 })
1259 reqStream.wantSomeHeaders(http.Header{
1260 "Server-Trailer-A": {"valuea"},
1261 "Server-Trailer-C": {"valuec"},
1262 "Undeclared-Trailer-Exception": {"should be sent"},
1263 })
1264 reqStream.wantClosed("request is complete")
1265 })
1266 }
1267
1268 func TestServerInfersHeaders(t *testing.T) {
1269 tests := []struct {
1270 name string
1271 flushedEarly bool
1272 responseStatus int
1273 does100Continue bool
1274 declaredHeader http.Header
1275 want http.Header
1276 }{
1277 {
1278 name: "infers undeclared headers",
1279 responseStatus: 200,
1280 declaredHeader: http.Header{
1281 "Some-Other-Header": {"some value"},
1282 },
1283 want: http.Header{
1284 "Date": {"Sat, 01 Jan 2000 00:00:00 GMT"},
1285 "Content-Type": {"text/html; charset=utf-8"},
1286 "Some-Other-Header": {"some value"},
1287 },
1288 },
1289 {
1290 name: "does not write over declared header",
1291 responseStatus: 200,
1292 declaredHeader: http.Header{
1293 "Date": {"some date"},
1294 "Content-Type": {"some content type"},
1295 "Some-Other-Header": {"some value"},
1296 },
1297 want: http.Header{
1298 "Date": {"some date"},
1299 "Content-Type": {"some content type"},
1300 "Some-Other-Header": {"some value"},
1301 },
1302 },
1303 {
1304 name: "does not infer content type for response with no body",
1305 responseStatus: 304,
1306 declaredHeader: http.Header{
1307 "Some-Other-Header": {"some value"},
1308 },
1309 want: http.Header{
1310 "Date": {"Sat, 01 Jan 2000 00:00:00 GMT"},
1311 "Some-Other-Header": {"some value"},
1312 },
1313 },
1314 {
1315
1316 name: "does not infer content type for response with declared content encoding",
1317 responseStatus: 200,
1318 declaredHeader: http.Header{
1319 "Content-Encoding": {"some encoding"},
1320 "Some-Other-Header": {"some value"},
1321 },
1322 want: http.Header{
1323 "Date": {"Sat, 01 Jan 2000 00:00:00 GMT"},
1324 "Content-Encoding": {"some encoding"},
1325 "Some-Other-Header": {"some value"},
1326 },
1327 },
1328 {
1329 name: "infers content type for response with empty content encoding",
1330 responseStatus: 200,
1331 declaredHeader: http.Header{
1332 "Content-Encoding": {""},
1333 "Some-Other-Header": {"some value"},
1334 },
1335 want: http.Header{
1336 "Date": {"Sat, 01 Jan 2000 00:00:00 GMT"},
1337 "Content-Encoding": {""},
1338 "Content-Type": {"text/html; charset=utf-8"},
1339 "Some-Other-Header": {"some value"},
1340 },
1341 },
1342 {
1343 name: "does not infer content type when header is flushed before body is written",
1344 responseStatus: 200,
1345 flushedEarly: true,
1346 declaredHeader: http.Header{
1347 "Some-Other-Header": {"some value"},
1348 },
1349 want: http.Header{
1350 "Date": {"Sat, 01 Jan 2000 00:00:00 GMT"},
1351 "Some-Other-Header": {"some value"},
1352 },
1353 },
1354 {
1355 name: "infers header for the header that comes after 100 continue",
1356 responseStatus: 200,
1357 does100Continue: true,
1358 declaredHeader: http.Header{
1359 "Some-Other-Header": {"some value"},
1360 },
1361 want: http.Header{
1362 "Date": {"Sat, 01 Jan 2000 00:00:00 GMT"},
1363 "Content-Type": {"text/html; charset=utf-8"},
1364 "Some-Other-Header": {"some value"},
1365 },
1366 },
1367 }
1368
1369 for _, tt := range tests {
1370 synctestSubtest(t, tt.name, func(t *testing.T) {
1371 body := []byte("<html>some html content</html>")
1372 streamIdle := make(chan bool)
1373 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1374 if tt.does100Continue {
1375 <-streamIdle
1376 io.ReadAll(r.Body)
1377 }
1378 for name, values := range tt.declaredHeader {
1379 for _, value := range values {
1380 w.Header().Add(name, value)
1381 }
1382 }
1383 w.WriteHeader(tt.responseStatus)
1384 if tt.flushedEarly {
1385 w.(http.Flusher).Flush()
1386 }
1387
1388
1389
1390 for _, b := range body {
1391 w.Write([]byte{b})
1392 }
1393 }))
1394 tc := ts.connect()
1395 tc.greet()
1396
1397 reqStream := tc.newStream(streamTypeRequest)
1398
1399 if tt.does100Continue {
1400 reqStream.writeHeaders(requestHeader(http.Header{
1401 "expect": {"100-continue"},
1402 }))
1403 reqStream.wantIdle("stream is idle until server sends an HTTP 100 status")
1404 streamIdle <- true
1405 reqStream.wantHeaders(http.Header{":status": {"100"}})
1406 }
1407
1408 reqStream.writeHeaders(requestHeader(nil))
1409 tt.want.Add(":status", strconv.Itoa(tt.responseStatus))
1410 reqStream.wantHeaders(tt.want)
1411 if responseCanHaveBody(tt.responseStatus) {
1412 reqStream.wantData(body)
1413 }
1414 reqStream.wantClosed("request is complete")
1415 })
1416 }
1417 }
1418
1419 func TestServerBuffersBodyWrite(t *testing.T) {
1420 tests := []struct {
1421 name string
1422 bodyLen int
1423 writeSize int
1424 flushes bool
1425 }{
1426 {
1427 name: "buffers small body content",
1428 bodyLen: defaultBodyBufferCap * 10,
1429 writeSize: 5,
1430 flushes: false,
1431 },
1432 {
1433 name: "does not buffer large body content",
1434 bodyLen: defaultBodyBufferCap * 10,
1435 writeSize: defaultBodyBufferCap * 2,
1436 flushes: false,
1437 },
1438 {
1439 name: "does not buffer flushed body content",
1440 bodyLen: defaultBodyBufferCap * 10,
1441 writeSize: 10,
1442 flushes: true,
1443 },
1444 }
1445 for _, tt := range tests {
1446 synctestSubtest(t, tt.name, func(t *testing.T) {
1447 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1448 for n := 0; n < tt.bodyLen; n += tt.writeSize {
1449 data := slices.Repeat([]byte("a"), min(tt.writeSize, tt.bodyLen-n))
1450 n, err := w.Write(data)
1451 if err != nil {
1452 t.Fatal(err)
1453 }
1454 if n != len(data) {
1455 t.Errorf("got %v bytes when writing in server handler, want %v", n, len(data))
1456 }
1457 if tt.flushes {
1458 w.(http.Flusher).Flush()
1459 }
1460 }
1461 }))
1462 tc := ts.connect()
1463 tc.greet()
1464
1465 reqStream := tc.newStream(streamTypeRequest)
1466 reqStream.writeHeaders(requestHeader(nil))
1467 reqStream.wantHeaders(nil)
1468 switch {
1469 case tt.writeSize > defaultBodyBufferCap:
1470
1471
1472 for n := 0; n < tt.bodyLen; n += tt.writeSize {
1473 reqStream.wantData(slices.Repeat([]byte("a"), min(tt.writeSize, tt.bodyLen-n)))
1474 }
1475 case tt.flushes:
1476 for n := 0; n < tt.bodyLen; n += tt.writeSize {
1477 reqStream.wantData(slices.Repeat([]byte("a"), min(tt.writeSize, tt.bodyLen-n)))
1478 }
1479 case tt.writeSize <= defaultBodyBufferCap:
1480 dataLen := defaultBodyBufferCap + tt.writeSize - (defaultBodyBufferCap % tt.writeSize)
1481 for n := 0; n < tt.bodyLen; n += dataLen {
1482 reqStream.wantData(slices.Repeat([]byte("a"), min(dataLen, tt.bodyLen-n)))
1483 }
1484 }
1485 reqStream.wantClosed("request is complete")
1486 })
1487 }
1488 }
1489
1490 func TestServer103EarlyHints(t *testing.T) {
1491 synctest.Test(t, func(t *testing.T) {
1492 body := []byte("some body")
1493 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1494 h := w.Header()
1495
1496 h.Add("Content-Length", "123")
1497 h.Add("Link", "</style.css>; rel=preload; as=style")
1498 h.Add("Link", "</script.js>; rel=preload; as=script")
1499 w.WriteHeader(http.StatusEarlyHints)
1500
1501 h.Add("Link", "</foo.js>; rel=preload; as=script")
1502 w.WriteHeader(http.StatusEarlyHints)
1503
1504 w.Write(body)
1505 w.WriteHeader(http.StatusEarlyHints)
1506 }))
1507 tc := ts.connect()
1508 tc.greet()
1509
1510 reqStream := tc.newStream(streamTypeRequest)
1511 reqStream.writeHeaders(requestHeader(nil))
1512 reqStream.wantHeaders(http.Header{
1513 ":status": {"103"},
1514 "Link": {
1515 "</style.css>; rel=preload; as=style",
1516 "</script.js>; rel=preload; as=script",
1517 },
1518 })
1519 reqStream.wantHeaders(http.Header{
1520 ":status": {"103"},
1521 "Link": {
1522 "</style.css>; rel=preload; as=style",
1523 "</script.js>; rel=preload; as=script",
1524 "</foo.js>; rel=preload; as=script",
1525 },
1526 })
1527 reqStream.wantSomeHeaders(http.Header{
1528 ":status": {"200"},
1529 "Content-Length": {"123"},
1530 })
1531 reqStream.wantData(body)
1532 reqStream.wantClosed("request is complete")
1533 })
1534 }
1535
1536 func TestServer304NotModified(t *testing.T) {
1537 synctest.Test(t, func(t *testing.T) {
1538 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1539 w.WriteHeader(http.StatusNotModified)
1540 if _, err := w.Write([]byte("body should not be allowed")); !errors.Is(err, http.ErrBodyNotAllowed) {
1541 t.Errorf("got %v error when calling Write after WriteHeader(304), want %v error", err, http.ErrBodyNotAllowed)
1542 }
1543 }))
1544 tc := ts.connect()
1545 tc.greet()
1546
1547 reqStream := tc.newStream(streamTypeRequest)
1548 reqStream.writeHeaders(requestHeader(nil))
1549 reqStream.wantSomeHeaders(http.Header{":status": {"304"}})
1550 reqStream.wantClosed("request is complete")
1551 })
1552 }
1553
1554 func TestServerInvalidPathHeader(t *testing.T) {
1555 for _, test := range []struct {
1556 name string
1557 path string
1558 }{{
1559 name: "empty",
1560 path: "",
1561 }, {
1562 name: "invalid char",
1563 path: "\x00",
1564 }, {
1565 name: "absolute url",
1566 path: "https://example.com/",
1567 }} {
1568 synctestSubtest(t, test.name, func(t *testing.T) {
1569 ts := newTestServer(t, nil)
1570 tc := ts.connect()
1571 tc.greet()
1572
1573 reqStream := tc.newStream(streamTypeRequest)
1574 reqStream.writeHeaders(requestHeader(http.Header{
1575 ":path": []string{test.path},
1576 }))
1577 reqStream.wantError(quic.StreamError(errH3MessageError))
1578 })
1579 }
1580 }
1581
1582 func TestServerOptionsMethod(t *testing.T) {
1583 synctest.Test(t, func(t *testing.T) {
1584 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
1585 tc := ts.connect()
1586 tc.greet()
1587
1588 reqStream := tc.newStream(streamTypeRequest)
1589 reqStream.writeHeaders(requestHeader(http.Header{
1590 ":method": []string{"OPTIONS"},
1591 ":path": []string{"*"},
1592 }))
1593 reqStream.wantSomeHeaders(http.Header{
1594 ":status": {"200"},
1595 })
1596 })
1597 }
1598
1599 func TestServerPastWriteDeadline(t *testing.T) {
1600 synctest.Test(t, func(t *testing.T) {
1601 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1602 ctl := http.NewResponseController(w)
1603 io.WriteString(w, "one")
1604 if err := ctl.Flush(); err != nil {
1605 t.Errorf("Flush() = %v, want nil", err)
1606 }
1607 time.Sleep(time.Second)
1608
1609 if err := ctl.SetWriteDeadline(time.Now().Add(-10 * time.Second)); err != nil {
1610 t.Errorf("SetWriteDeadline() = %v, want nil", err)
1611 }
1612 var err error
1613 _, err = io.WriteString(w, "x")
1614 if err == nil {
1615 err = ctl.Flush()
1616 }
1617 if !errors.Is(err, os.ErrDeadlineExceeded) {
1618 t.Errorf("got write err %v, want %v", err, os.ErrDeadlineExceeded)
1619 }
1620
1621
1622 if err := ctl.SetWriteDeadline(time.Now().Add(10 * time.Second)); err != nil {
1623 t.Errorf("SetWriteDeadline() = %v, want nil", err)
1624 }
1625 _, err = io.WriteString(w, "x")
1626 if err == nil {
1627 err = ctl.Flush()
1628 }
1629 if !errors.Is(err, os.ErrDeadlineExceeded) {
1630 t.Errorf("got write err %v (after extend), want %v", err, os.ErrDeadlineExceeded)
1631 }
1632 }))
1633 tc := ts.connect()
1634 tc.greet()
1635
1636 reqStream := tc.newStream(streamTypeRequest)
1637 reqStream.writeHeaders(requestHeader(nil))
1638 reqStream.wantSomeHeaders(http.Header{":status": {"200"}})
1639 reqStream.wantData([]byte("one"))
1640 time.Sleep(2 * time.Second)
1641 synctest.Wait()
1642 reqStream.wantError(quic.StreamError(errH3RequestCancelled))
1643 })
1644 }
1645
1646 func TestServerFutureWriteDeadline(t *testing.T) {
1647 synctest.Test(t, func(t *testing.T) {
1648 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1649 ctl := http.NewResponseController(w)
1650 io.WriteString(w, "one")
1651 if err := ctl.Flush(); err != nil {
1652 t.Errorf("Flush() = %v, want nil", err)
1653 }
1654
1655
1656 if err := ctl.SetWriteDeadline(time.Now().Add(time.Second)); err != nil {
1657 t.Errorf("SetWriteDeadline() = %v, want nil", err)
1658 }
1659 io.WriteString(w, "two")
1660 if err := ctl.Flush(); err != nil {
1661 t.Errorf("Flush() = %v, want nil", err)
1662 }
1663
1664
1665 if err := ctl.SetWriteDeadline(time.Now().Add(3 * time.Second)); err != nil {
1666 t.Errorf("SetWriteDeadline() = %v, want nil", err)
1667 }
1668
1669 time.Sleep(2 * time.Second)
1670 io.WriteString(w, "three")
1671 if err := ctl.Flush(); err != nil {
1672 t.Errorf("Flush() = %v, want nil", err)
1673 }
1674
1675
1676 time.Sleep(2 * time.Second)
1677 var err error
1678 _, err = io.WriteString(w, "x")
1679 if err == nil {
1680 err = ctl.Flush()
1681 }
1682 if !errors.Is(err, os.ErrDeadlineExceeded) {
1683 t.Errorf("got write err %v, want %v", err, os.ErrDeadlineExceeded)
1684 }
1685
1686
1687 if err := ctl.SetWriteDeadline(time.Time{}); err != nil {
1688 t.Errorf("SetWriteDeadline() = %v, want nil", err)
1689 }
1690 _, err = io.WriteString(w, "x")
1691 if err == nil {
1692 err = ctl.Flush()
1693 }
1694 if !errors.Is(err, os.ErrDeadlineExceeded) {
1695 t.Errorf("got write err %v (after extend), want %v", err, os.ErrDeadlineExceeded)
1696 }
1697 }))
1698 tc := ts.connect()
1699 tc.greet()
1700
1701 reqStream := tc.newStream(streamTypeRequest)
1702 reqStream.writeHeaders(requestHeader(nil))
1703 reqStream.wantSomeHeaders(http.Header{":status": {"200"}})
1704 reqStream.wantData([]byte("one"))
1705 reqStream.wantData([]byte("two"))
1706 time.Sleep(3 * time.Second)
1707 reqStream.wantData([]byte("three"))
1708 time.Sleep(3 * time.Second)
1709 reqStream.wantError(quic.StreamError(errH3RequestCancelled))
1710 })
1711 }
1712
1713 func TestServerPastReadDeadline(t *testing.T) {
1714 synctest.Test(t, func(t *testing.T) {
1715 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1716 ctl := http.NewResponseController(w)
1717 b := make([]byte, 3)
1718 if _, err := io.ReadFull(r.Body, b); err != nil || string(b) != "one" {
1719 t.Errorf("Read() got (%q, %v), want (%q, nil)", b, err, "one")
1720 }
1721
1722 if err := ctl.SetReadDeadline(time.Now().Add(-10 * time.Second)); err != nil {
1723 t.Errorf("SetReadDeadline() = %v, want nil", err)
1724 }
1725 _, err := io.ReadAll(r.Body)
1726 if !errors.Is(err, os.ErrDeadlineExceeded) {
1727 t.Errorf("got read err %v, want %v", err, os.ErrDeadlineExceeded)
1728 }
1729
1730
1731 if err := ctl.SetReadDeadline(time.Now().Add(10 * time.Second)); err != nil {
1732 t.Errorf("SetReadDeadline() = %v, want nil", err)
1733 }
1734 _, err = io.ReadAll(r.Body)
1735 if !errors.Is(err, os.ErrDeadlineExceeded) {
1736 t.Errorf("got read err %v (after extend), want %v", err, os.ErrDeadlineExceeded)
1737 }
1738 }))
1739 tc := ts.connect()
1740 tc.greet()
1741
1742 reqStream := tc.newStream(streamTypeRequest)
1743 reqStream.writeHeaders(requestHeader(nil))
1744 reqStream.writeData([]byte("one"))
1745 synctest.Wait()
1746 })
1747 }
1748
1749 func TestServerFutureReadDeadline(t *testing.T) {
1750 synctest.Test(t, func(t *testing.T) {
1751 ts := newTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1752 ctl := http.NewResponseController(w)
1753 b := make([]byte, 3)
1754 if _, err := io.ReadFull(r.Body, b); err != nil || string(b) != "one" {
1755 t.Errorf("Read() got (%q, %v), want (%q, nil)", b, err, "one")
1756 }
1757
1758
1759 if err := ctl.SetReadDeadline(time.Now().Add(2 * time.Second)); err != nil {
1760 t.Errorf("SetReadDeadline() = %v, want nil", err)
1761 }
1762 b2 := make([]byte, 3)
1763 if _, err := io.ReadFull(r.Body, b2); err != nil || string(b2) != "two" {
1764 t.Errorf("Read() got (%q, %v), want (%q, nil)", b2, err, "two")
1765 }
1766
1767
1768 if err := ctl.SetReadDeadline(time.Now().Add(4 * time.Second)); err != nil {
1769 t.Errorf("SetReadDeadline() = %v, want nil", err)
1770 }
1771
1772 time.Sleep(2 * time.Second)
1773 b3 := make([]byte, 5)
1774 if _, err := io.ReadFull(r.Body, b3); err != nil || string(b3) != "three" {
1775 t.Errorf("Read() got (%q, %v), want (%q, nil)", b3, err, "three")
1776 }
1777
1778
1779 time.Sleep(3 * time.Second)
1780 _, err := io.ReadAll(r.Body)
1781 if !errors.Is(err, os.ErrDeadlineExceeded) {
1782 t.Errorf("got read err %v, want %v", err, os.ErrDeadlineExceeded)
1783 }
1784
1785
1786 if err := ctl.SetReadDeadline(time.Time{}); err != nil {
1787 t.Errorf("SetReadDeadline() = %v, want nil", err)
1788 }
1789 _, err = io.ReadAll(r.Body)
1790 if !errors.Is(err, os.ErrDeadlineExceeded) {
1791 t.Errorf("got read err %v (after extend), want %v", err, os.ErrDeadlineExceeded)
1792 }
1793 }))
1794 tc := ts.connect()
1795 tc.greet()
1796
1797 reqStream := tc.newStream(streamTypeRequest)
1798 reqStream.writeHeaders(requestHeader(nil))
1799 reqStream.writeData([]byte("one"))
1800
1801 time.Sleep(time.Second)
1802 reqStream.writeData([]byte("two"))
1803 synctest.Wait()
1804
1805 time.Sleep(time.Second)
1806 reqStream.writeData([]byte("three"))
1807 synctest.Wait()
1808
1809 time.Sleep(4 * time.Second)
1810 })
1811 }
1812
1813 func TestServerReadHeaderTimeout(t *testing.T) {
1814 synctest.Test(t, func(t *testing.T) {
1815 timeout := 10 * time.Second
1816 ts := newTestServer(t, nil)
1817 ts.s.srv1.ReadHeaderTimeout = timeout
1818 tc := ts.connect()
1819 tc.greet()
1820
1821
1822 reqStream := tc.newStream(streamTypeRequest)
1823 reqStream.writeVarint(int64(frameTypeHeaders))
1824 if err := reqStream.Flush(); err != nil {
1825 t.Fatalf("Flush() = %v, want nil", err)
1826 }
1827
1828
1829
1830 time.Sleep(timeout - 1)
1831 reqStream.wantIdle("timeout has not been reached")
1832 time.Sleep(1)
1833 reqStream.wantError(quic.StreamError(errH3RequestRejected))
1834 if tc.nextHandlerCall() != nil {
1835 t.Error("server handler should not be called")
1836 }
1837 })
1838 }
1839
1840 func TestServerReadTimeout(t *testing.T) {
1841 synctest.Test(t, func(t *testing.T) {
1842 timeout := 10 * time.Second
1843 ts := newTestServer(t, nil)
1844 ts.s.srv1.ReadTimeout = timeout
1845 tc := ts.connect()
1846 tc.greet()
1847
1848 reqStream := tc.newStream(streamTypeRequest)
1849 reqStream.writeHeaders(requestHeader(nil))
1850 reqStream.writeData([]byte("some body"))
1851 call := tc.nextHandlerCall()
1852
1853
1854 time.Sleep(timeout - 1)
1855 synctest.Wait()
1856 if _, err := call.req.Body.Read(make([]byte, 1)); err != nil {
1857 t.Errorf("Read() before timeout = %v, want nil", err)
1858 }
1859
1860
1861
1862
1863
1864 time.Sleep(1)
1865 synctest.Wait()
1866 if _, err := call.req.Body.Read(make([]byte, 1)); !errors.Is(err, os.ErrDeadlineExceeded) {
1867 t.Errorf("Read() after timeout = %v, want os.ErrDeadlineExceeded", err)
1868 }
1869 call.w.Write([]byte("some body"))
1870 call.exit()
1871 reqStream.wantSomeHeaders(http.Header{":status": {"200"}})
1872 reqStream.wantData([]byte("some body"))
1873 reqStream.wantClosed("clean close expected")
1874 })
1875 }
1876
1877 func TestServerReadTimeoutInProgress(t *testing.T) {
1878 synctest.Test(t, func(t *testing.T) {
1879 timeout := 10 * time.Second
1880 ts := newTestServer(t, nil)
1881 ts.s.srv1.ReadTimeout = timeout
1882 tc := ts.connect()
1883 tc.greet()
1884
1885 reqStream := tc.newStream(streamTypeRequest)
1886 reqStream.writeHeaders(requestHeader(nil))
1887 reqStream.Flush()
1888 call := tc.nextHandlerCall()
1889
1890
1891
1892 start := time.Now()
1893 _, err := call.req.Body.Read(make([]byte, 1))
1894 if !errors.Is(err, os.ErrDeadlineExceeded) {
1895 t.Errorf("Read error = %v, want os.ErrDeadlineExceeded", err)
1896 }
1897 if got, want := time.Since(start), timeout; got != want {
1898 t.Errorf("Read blocked for %v, want %v", got, want)
1899 }
1900 call.exit()
1901 })
1902 }
1903
1904 func TestServerWriteTimeout(t *testing.T) {
1905 synctest.Test(t, func(t *testing.T) {
1906 timeout := 10 * time.Second
1907 ts := newTestServer(t, nil)
1908 ts.s.srv1.WriteTimeout = timeout
1909 tc := ts.connect()
1910 tc.greet()
1911
1912 reqStream := tc.newStream(streamTypeRequest)
1913 reqStream.writeHeaders(requestHeader(nil))
1914 call := tc.nextHandlerCall()
1915 body := make([]byte, defaultBodyBufferCap+1)
1916
1917
1918 time.Sleep(timeout - 1)
1919 synctest.Wait()
1920 if _, err := call.w.Write(body); err != nil {
1921 t.Errorf("Write() before timeout = %v, want nil", err)
1922 }
1923 call.w.(http.Flusher).Flush()
1924 reqStream.wantSomeHeaders(http.Header{":status": {"200"}})
1925 reqStream.wantData(body)
1926 reqStream.wantIdle("timeout has not been reached")
1927
1928
1929
1930 time.Sleep(1)
1931 synctest.Wait()
1932 if _, err := call.w.Write(body); !errors.Is(err, os.ErrDeadlineExceeded) {
1933 t.Errorf("Write() after timeout = %v, want os.ErrDeadlineExceeded", err)
1934 }
1935 call.exit()
1936 reqStream.wantError(quic.StreamError(errH3RequestCancelled))
1937 })
1938 }
1939
1940 func TestServerWriteTimeoutInProgress(t *testing.T) {
1941 synctest.Test(t, func(t *testing.T) {
1942 timeout := 10 * time.Second
1943 ts := newTestServer(t, nil)
1944 ts.s.srv1.WriteTimeout = timeout
1945 tc := ts.connect()
1946 tc.greet()
1947
1948 reqStream := tc.newStream(streamTypeRequest)
1949 reqStream.writeHeaders(requestHeader(nil))
1950 reqStream.Flush()
1951 call := tc.nextHandlerCall()
1952
1953
1954
1955 start := time.Now()
1956 var err error
1957 for err == nil {
1958 _, err = call.w.Write([]byte("endless body"))
1959 }
1960 if !errors.Is(err, os.ErrDeadlineExceeded) {
1961 t.Errorf("Write error = %v, want os.ErrDeadlineExceeded", err)
1962 }
1963 if got, want := time.Since(start), timeout; got != want {
1964 t.Errorf("Write blocked for %v, want %v", got, want)
1965 }
1966 call.exit()
1967 })
1968 }
1969
1970 type testServer struct {
1971 t testing.TB
1972 s *server
1973 tn testNet
1974 testHandler *testServerHandler
1975 *testQUICEndpoint
1976
1977 addr netip.AddrPort
1978 }
1979
1980 type testQUICEndpoint struct {
1981 t testing.TB
1982 e *quic.Endpoint
1983 }
1984
1985 type testServerConn struct {
1986 ts *testServer
1987
1988 *testQUICConn
1989 control *testQUICStream
1990 localAddr netip.AddrPort
1991 }
1992
1993 type testServerHandler struct {
1994 ts *testServer
1995 callsMu sync.Mutex
1996 calls []*serverHandlerCall
1997 }
1998
1999
2000 type serverHandlerCall struct {
2001 w http.ResponseWriter
2002 req *http.Request
2003 closeOnce sync.Once
2004 ch chan func()
2005 }
2006
2007 func newTestServer(t testing.TB, handler http.Handler) *testServer {
2008 t.Helper()
2009 ts := &testServer{
2010 t: t,
2011 }
2012 if handler == nil {
2013 ts.testHandler = &testServerHandler{
2014 ts: ts,
2015 calls: []*serverHandlerCall{},
2016 }
2017 handler = ts.testHandler
2018 }
2019 ts.s = &server{
2020 srv1: &http.Server{},
2021 }
2022 e := ts.tn.newQUICEndpoint(t, &quic.Config{
2023 TLSConfig: testTLSConfig,
2024 })
2025 ts.addr = e.LocalAddr()
2026 go ts.s.serve(t.Context(), e, handler)
2027 return ts
2028 }
2029
2030 func (ts *testServer) connect() *testServerConn {
2031 ts.t.Helper()
2032 config := &quic.Config{TLSConfig: testTLSConfig}
2033 e := ts.tn.newQUICEndpoint(ts.t, nil)
2034 qconn, err := e.Dial(ts.t.Context(), "udp", ts.addr.String(), config)
2035 if err != nil {
2036 ts.t.Fatal(err)
2037 }
2038 tc := &testServerConn{
2039 ts: ts,
2040 testQUICConn: newTestQUICConn(ts.t, qconn),
2041 localAddr: e.LocalAddr(),
2042 }
2043 synctest.Wait()
2044 return tc
2045 }
2046
2047
2048 func (tc *testServerConn) greet() {
2049
2050 tc.control = tc.newStream(streamTypeControl)
2051 tc.control.writeVarint(int64(frameTypeSettings))
2052 tc.control.writeVarint(0)
2053 tc.control.Flush()
2054 synctest.Wait()
2055 }
2056
2057
2058
2059 func (tc *testServerConn) nextHandlerCall() *serverHandlerCall {
2060 h := tc.ts.testHandler
2061 if h == nil {
2062 tc.t.Fatal("nextHandlerCall is called for a testServer with non-nil handler")
2063 }
2064 tc.t.Helper()
2065 synctest.Wait()
2066 h.callsMu.Lock()
2067 defer h.callsMu.Unlock()
2068 for i, call := range h.calls {
2069 if call.req.RemoteAddr == tc.localAddr.String() {
2070 h.calls = append(h.calls[:i], h.calls[i+1:]...)
2071 return call
2072 }
2073 }
2074 return nil
2075 }
2076
2077 func (h *testServerHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
2078 call := &serverHandlerCall{
2079 w: w,
2080 req: req,
2081 ch: make(chan func()),
2082 }
2083 h.ts.t.Cleanup(call.exit)
2084 h.callsMu.Lock()
2085 h.calls = append(h.calls, call)
2086 h.callsMu.Unlock()
2087 for f := range call.ch {
2088 f()
2089 }
2090 }
2091
2092
2093 func (call *serverHandlerCall) do(f func(http.ResponseWriter, *http.Request)) {
2094 donec := make(chan struct{})
2095 call.ch <- func() {
2096 defer close(donec)
2097 f(call.w, call.req)
2098 }
2099 <-donec
2100 }
2101
2102
2103 func (call *serverHandlerCall) exit() {
2104 call.closeOnce.Do(func() {
2105 close(call.ch)
2106 })
2107 }
2108
View as plain text