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