github.com/google/go-safeweb@v0.0.0-20231219055052-64d8cfc90fbb/internal/requesttesting/headers/host_test.go (about)

     1  // Copyright 2020 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //	https://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package headers
    16  
    17  import (
    18  	"context"
    19  	"net/http"
    20  	"testing"
    21  
    22  	"github.com/google/go-safeweb/internal/requesttesting"
    23  )
    24  
    25  func TestHostHeader(t *testing.T) {
    26  	var tests = []struct {
    27  		name    string
    28  		request []byte
    29  		want    string
    30  	}{
    31  		{
    32  			name: "Basic",
    33  			request: []byte("GET / HTTP/1.1\r\n" +
    34  				"Host: localhost:8080\r\n" +
    35  				"\r\n"),
    36  			want: "localhost:8080",
    37  		},
    38  		{
    39  			// https://tools.ietf.org/html/rfc7230#section-5.3.2
    40  			name: "AbsoluteFormURL",
    41  			request: []byte("GET http://y.com/asdf HTTP/1.1\r\n" +
    42  				"Host: x.com\r\n" +
    43  				"\r\n"),
    44  			want: "y.com",
    45  		},
    46  		{
    47  			// https://tools.ietf.org/html/rfc7230#section-5.3.3
    48  			name: "AuthorityForm",
    49  			request: []byte("GET y.com:123/asdf HTTP/1.1\r\n" +
    50  				"Host: x.com\r\n" +
    51  				"\r\n"),
    52  			want: "x.com",
    53  		},
    54  		{
    55  			name: "NoDoubleSlash",
    56  			request: []byte("GET http:y.com/asdf HTTP/1.1\r\n" +
    57  				"Host: x.com\r\n" +
    58  				"\r\n"),
    59  			want: "x.com",
    60  		},
    61  		{
    62  			name: "NoSchemaOnlyDoubleSlash",
    63  			request: []byte("GET //y.com/asdf HTTP/1.1\r\n" +
    64  				"Host: x.com\r\n" +
    65  				"\r\n"),
    66  			want: "x.com",
    67  		},
    68  	}
    69  
    70  	for _, tt := range tests {
    71  		t.Run(tt.name, func(t *testing.T) {
    72  			resp, err := requesttesting.MakeRequest(context.Background(), tt.request, func(r *http.Request) {
    73  				if len(r.Header) != 0 {
    74  					t.Errorf("len(r.Header) got: %v want: 0", len(r.Header))
    75  				}
    76  
    77  				if r.Host != tt.want {
    78  					t.Errorf("r.Host got: %q want: %q", r.Host, tt.want)
    79  				}
    80  			})
    81  			if err != nil {
    82  				t.Fatalf("MakeRequest() got err: %v", err)
    83  			}
    84  
    85  			if got, want := extractStatus(resp), statusOK; !matchStatus(got, want) {
    86  				t.Errorf("status code got: %q want: %q", got, want)
    87  			}
    88  		})
    89  	}
    90  }
    91  
    92  func TestHostHeaderMultiple(t *testing.T) {
    93  	request := []byte("GET / HTTP/1.1\r\n" +
    94  		"Host: x.com\r\n" +
    95  		"Host: y.com\r\n" +
    96  		"\r\n")
    97  
    98  	resp, err := requesttesting.MakeRequest(context.Background(), request, nil)
    99  	if err != nil {
   100  		t.Fatalf("MakeRequest() got err: %v", err)
   101  	}
   102  
   103  	if got, want := extractStatus(resp), statusBadRequestPrefix; !matchStatus(got, want) {
   104  		t.Errorf("status code got: %q want: %q", got, want)
   105  	}
   106  }
   107  
   108  func TestAbsoluteFormURLInvalidSchema(t *testing.T) {
   109  	// When sending a request using the absolute
   110  	// form as the request target, any schema is currently
   111  	// accepted.
   112  	//
   113  	// The desired behavior would instead be to only
   114  	// accept http or https as schemas and to respond
   115  	// with a 400 (Bad Request) when the server receives
   116  	// any other schema.
   117  
   118  	request := []byte("GET x://y.com/asdf HTTP/1.1\r\n" +
   119  		"Host: x.com\r\n" +
   120  		"\r\n")
   121  
   122  	t.Run("Current behavior", func(t *testing.T) {
   123  		resp, err := requesttesting.MakeRequest(context.Background(), request, func(r *http.Request) {
   124  			if len(r.Header) != 0 {
   125  				t.Errorf("len(r.Header) got: %v want: 0", len(r.Header))
   126  			}
   127  
   128  			if want := "y.com"; r.Host != want {
   129  				t.Errorf("r.Host got: %q want: %q", r.Host, want)
   130  			}
   131  		})
   132  		if err != nil {
   133  			t.Fatalf("MakeRequest() got err: %v want: nil", err)
   134  		}
   135  
   136  		if got, want := extractStatus(resp), statusOK; !matchStatus(got, want) {
   137  			t.Errorf("status code got: %q want: %q", got, want)
   138  		}
   139  	})
   140  
   141  	t.Run("Desired behavior", func(t *testing.T) {
   142  		t.Skip()
   143  		resp, err := requesttesting.MakeRequest(context.Background(), request, func(r *http.Request) {
   144  			t.Error("Expected handler to not be called!")
   145  		})
   146  		if err != nil {
   147  			t.Fatalf("MakeRequest() got err: %v want: nil", err)
   148  		}
   149  
   150  		if got, want := extractStatus(resp), statusBadRequestPrefix; !matchStatus(got, want) {
   151  			t.Errorf("status code got: %q want: %q", got, want)
   152  		}
   153  	})
   154  }