@@ -2201,7 +2201,7 @@ func TestClientWriteShutdown(t *testing.T) {
2201
2201
// buffered before chunk headers are added, not after chunk headers.
2202
2202
func TestServerBufferedChunking (t * testing.T ) {
2203
2203
conn := new (testConn )
2204
- conn .readBuf .Write ([]byte ("GET / HTTP/1.1\r \n \r \n " ))
2204
+ conn .readBuf .Write ([]byte ("GET / HTTP/1.1\r \n Host: foo \r \ n\r \n " ))
2205
2205
conn .closec = make (chan bool , 1 )
2206
2206
ls := & oneConnListener {conn }
2207
2207
go Serve (ls , HandlerFunc (func (rw ResponseWriter , req * Request ) {
@@ -2934,9 +2934,9 @@ func TestCodesPreventingContentTypeAndBody(t *testing.T) {
2934
2934
"GET / HTTP/1.0" ,
2935
2935
"GET /header HTTP/1.0" ,
2936
2936
"GET /more HTTP/1.0" ,
2937
- "GET / HTTP/1.1" ,
2938
- "GET /header HTTP/1.1" ,
2939
- "GET /more HTTP/1.1" ,
2937
+ "GET / HTTP/1.1\n Host: foo " ,
2938
+ "GET /header HTTP/1.1\n Host: foo " ,
2939
+ "GET /more HTTP/1.1\n Host: foo " ,
2940
2940
} {
2941
2941
got := ht .rawResponse (req )
2942
2942
wantStatus := fmt .Sprintf ("%d %s" , code , StatusText (code ))
@@ -2957,7 +2957,7 @@ func TestContentTypeOkayOn204(t *testing.T) {
2957
2957
w .Header ().Set ("Content-Type" , "foo/bar" )
2958
2958
w .WriteHeader (204 )
2959
2959
}))
2960
- got := ht .rawResponse ("GET / HTTP/1.1" )
2960
+ got := ht .rawResponse ("GET / HTTP/1.1\n Host: foo " )
2961
2961
if ! strings .Contains (got , "Content-Type: foo/bar" ) {
2962
2962
t .Errorf ("Response = %q; want Content-Type: foo/bar" , got )
2963
2963
}
@@ -3628,6 +3628,54 @@ func testHandlerSetsBodyNil(t *testing.T, h2 bool) {
3628
3628
}
3629
3629
}
3630
3630
3631
+ // Test that we validate the Host header.
3632
+ func TestServerValidatesHostHeader (t * testing.T ) {
3633
+ tests := []struct {
3634
+ proto string
3635
+ host string
3636
+ want int
3637
+ }{
3638
+ {"HTTP/1.1" , "" , 400 },
3639
+ {"HTTP/1.1" , "Host: \r \n " , 200 },
3640
+ {"HTTP/1.1" , "Host: 1.2.3.4\r \n " , 200 },
3641
+ {"HTTP/1.1" , "Host: foo.com\r \n " , 200 },
3642
+ {"HTTP/1.1" , "Host: foo-bar_baz.com\r \n " , 200 },
3643
+ {"HTTP/1.1" , "Host: foo.com:80\r \n " , 200 },
3644
+ {"HTTP/1.1" , "Host: ::1\r \n " , 200 },
3645
+ {"HTTP/1.1" , "Host: [::1]\r \n " , 200 }, // questionable without port, but accept it
3646
+ {"HTTP/1.1" , "Host: [::1]:80\r \n " , 200 },
3647
+ {"HTTP/1.1" , "Host: [::1%25en0]:80\r \n " , 200 },
3648
+ {"HTTP/1.1" , "Host: 1.2.3.4\r \n " , 200 },
3649
+ {"HTTP/1.1" , "Host: \x06 \r \n " , 400 },
3650
+ {"HTTP/1.1" , "Host: \xff \r \n " , 400 },
3651
+ {"HTTP/1.1" , "Host: {\r \n " , 400 },
3652
+ {"HTTP/1.1" , "Host: }\r \n " , 400 },
3653
+ {"HTTP/1.1" , "Host: first\r \n Host: second\r \n " , 400 },
3654
+
3655
+ // HTTP/1.0 can lack a host header, but if present
3656
+ // must play by the rules too:
3657
+ {"HTTP/1.0" , "" , 200 },
3658
+ {"HTTP/1.0" , "Host: first\r \n Host: second\r \n " , 400 },
3659
+ {"HTTP/1.0" , "Host: \xff \r \n " , 400 },
3660
+ }
3661
+ for _ , tt := range tests {
3662
+ conn := & testConn {closec : make (chan bool )}
3663
+ io .WriteString (& conn .readBuf , "GET / " + tt .proto + "\r \n " + tt .host + "\r \n " )
3664
+
3665
+ ln := & oneConnListener {conn }
3666
+ go Serve (ln , HandlerFunc (func (ResponseWriter , * Request ) {}))
3667
+ <- conn .closec
3668
+ res , err := ReadResponse (bufio .NewReader (& conn .writeBuf ), nil )
3669
+ if err != nil {
3670
+ t .Errorf ("For %s %q, ReadResponse: %v" , tt .proto , tt .host , res )
3671
+ continue
3672
+ }
3673
+ if res .StatusCode != tt .want {
3674
+ t .Errorf ("For %s %q, Status = %d; want %d" , tt .proto , tt .host , res .StatusCode , tt .want )
3675
+ }
3676
+ }
3677
+ }
3678
+
3631
3679
func BenchmarkClientServer (b * testing.B ) {
3632
3680
b .ReportAllocs ()
3633
3681
b .StopTimer ()
0 commit comments