github.com/spotmaxtech/k8s-apimachinery-v0260@v0.0.1/pkg/util/proxy/upgradeaware_test.go (about)

     1  /*
     2  Copyright 2017 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package proxy
    18  
    19  import (
    20  	"bufio"
    21  	"bytes"
    22  	"compress/gzip"
    23  	"context"
    24  	"crypto/tls"
    25  	"crypto/x509"
    26  	"errors"
    27  	"fmt"
    28  	"io"
    29  	"io/ioutil"
    30  	"net"
    31  	"net/http"
    32  	"net/http/httptest"
    33  	"net/http/httputil"
    34  	"net/url"
    35  	"reflect"
    36  	"strconv"
    37  	"strings"
    38  	"testing"
    39  	"time"
    40  
    41  	"github.com/stretchr/testify/assert"
    42  	"github.com/stretchr/testify/require"
    43  
    44  	"golang.org/x/net/websocket"
    45  
    46  	"github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/util/httpstream"
    47  	utilnet "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/util/net"
    48  )
    49  
    50  const fakeStatusCode = 567
    51  
    52  type fakeResponder struct {
    53  	t      *testing.T
    54  	called bool
    55  	err    error
    56  	// called chan error
    57  	w http.ResponseWriter
    58  }
    59  
    60  func (r *fakeResponder) Error(w http.ResponseWriter, req *http.Request, err error) {
    61  	if r.called {
    62  		r.t.Errorf("Error responder called again!\nprevious error: %v\nnew error: %v", r.err, err)
    63  	}
    64  
    65  	w.WriteHeader(fakeStatusCode)
    66  	_, writeErr := w.Write([]byte(err.Error()))
    67  	assert.NoError(r.t, writeErr)
    68  
    69  	r.called = true
    70  	r.err = err
    71  }
    72  
    73  type fakeConn struct {
    74  	err error // The error to return when io is performed over the connection.
    75  }
    76  
    77  func (f *fakeConn) Read([]byte) (int, error)        { return 0, f.err }
    78  func (f *fakeConn) Write([]byte) (int, error)       { return 0, f.err }
    79  func (f *fakeConn) Close() error                    { return nil }
    80  func (fakeConn) LocalAddr() net.Addr                { return nil }
    81  func (fakeConn) RemoteAddr() net.Addr               { return nil }
    82  func (fakeConn) SetDeadline(t time.Time) error      { return nil }
    83  func (fakeConn) SetReadDeadline(t time.Time) error  { return nil }
    84  func (fakeConn) SetWriteDeadline(t time.Time) error { return nil }
    85  
    86  type SimpleBackendHandler struct {
    87  	requestURL     url.URL
    88  	requestHost    string
    89  	requestHeader  http.Header
    90  	requestBody    []byte
    91  	requestMethod  string
    92  	responseBody   string
    93  	responseHeader map[string]string
    94  	t              *testing.T
    95  }
    96  
    97  func (s *SimpleBackendHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
    98  	s.requestURL = *req.URL
    99  	s.requestHost = req.Host
   100  	s.requestHeader = req.Header
   101  	s.requestMethod = req.Method
   102  	var err error
   103  	s.requestBody, err = ioutil.ReadAll(req.Body)
   104  	if err != nil {
   105  		s.t.Errorf("Unexpected error: %v", err)
   106  		return
   107  	}
   108  
   109  	if s.responseHeader != nil {
   110  		for k, v := range s.responseHeader {
   111  			w.Header().Add(k, v)
   112  		}
   113  	}
   114  	w.Write([]byte(s.responseBody))
   115  }
   116  
   117  func validateParameters(t *testing.T, name string, actual url.Values, expected map[string]string) {
   118  	for k, v := range expected {
   119  		actualValue, ok := actual[k]
   120  		if !ok {
   121  			t.Errorf("%s: Expected parameter %s not received", name, k)
   122  			continue
   123  		}
   124  		if actualValue[0] != v {
   125  			t.Errorf("%s: Parameter %s values don't match. Actual: %#v, Expected: %s",
   126  				name, k, actualValue, v)
   127  		}
   128  	}
   129  }
   130  
   131  func validateHeaders(t *testing.T, name string, actual http.Header, expected map[string]string, notExpected []string) {
   132  	for k, v := range expected {
   133  		actualValue, ok := actual[k]
   134  		if !ok {
   135  			t.Errorf("%s: Expected header %s not received", name, k)
   136  			continue
   137  		}
   138  		if actualValue[0] != v {
   139  			t.Errorf("%s: Header %s values don't match. Actual: %s, Expected: %s",
   140  				name, k, actualValue, v)
   141  		}
   142  	}
   143  	if notExpected == nil {
   144  		return
   145  	}
   146  	for _, h := range notExpected {
   147  		if _, present := actual[h]; present {
   148  			t.Errorf("%s: unexpected header: %s", name, h)
   149  		}
   150  	}
   151  }
   152  
   153  func TestServeHTTP(t *testing.T) {
   154  	tests := []struct {
   155  		name                  string
   156  		method                string
   157  		requestPath           string
   158  		expectedPath          string
   159  		requestBody           string
   160  		requestParams         map[string]string
   161  		requestHeader         map[string]string
   162  		responseHeader        map[string]string
   163  		expectedRespHeader    map[string]string
   164  		notExpectedRespHeader []string
   165  		upgradeRequired       bool
   166  		appendLocationPath    bool
   167  		expectError           func(err error) bool
   168  		useLocationHost       bool
   169  	}{
   170  		{
   171  			name:         "root path, simple get",
   172  			method:       "GET",
   173  			requestPath:  "/",
   174  			expectedPath: "/",
   175  		},
   176  		{
   177  			name:            "no upgrade header sent",
   178  			method:          "GET",
   179  			requestPath:     "/",
   180  			upgradeRequired: true,
   181  			expectError: func(err error) bool {
   182  				return err != nil && strings.Contains(err.Error(), "Upgrade request required")
   183  			},
   184  		},
   185  		{
   186  			name:         "simple path, get",
   187  			method:       "GET",
   188  			requestPath:  "/path/to/test",
   189  			expectedPath: "/path/to/test",
   190  		},
   191  		{
   192  			name:          "request params",
   193  			method:        "POST",
   194  			requestPath:   "/some/path/",
   195  			expectedPath:  "/some/path/",
   196  			requestParams: map[string]string{"param1": "value/1", "param2": "value%2"},
   197  			requestBody:   "test request body",
   198  		},
   199  		{
   200  			name:          "request headers",
   201  			method:        "PUT",
   202  			requestPath:   "/some/path",
   203  			expectedPath:  "/some/path",
   204  			requestHeader: map[string]string{"Header1": "value1", "Header2": "value2"},
   205  		},
   206  		{
   207  			name:         "empty path - slash should be added",
   208  			method:       "GET",
   209  			requestPath:  "",
   210  			expectedPath: "/",
   211  		},
   212  		{
   213  			name:         "remove CORS headers",
   214  			method:       "GET",
   215  			requestPath:  "/some/path",
   216  			expectedPath: "/some/path",
   217  			responseHeader: map[string]string{
   218  				"Header1":                      "value1",
   219  				"Access-Control-Allow-Origin":  "some.server",
   220  				"Access-Control-Allow-Methods": "GET"},
   221  			expectedRespHeader: map[string]string{
   222  				"Header1": "value1",
   223  			},
   224  			notExpectedRespHeader: []string{
   225  				"Access-Control-Allow-Origin",
   226  				"Access-Control-Allow-Methods",
   227  			},
   228  		},
   229  		{
   230  			name:            "use location host",
   231  			method:          "GET",
   232  			requestPath:     "/some/path",
   233  			expectedPath:    "/some/path",
   234  			useLocationHost: true,
   235  		},
   236  		{
   237  			name:            "use location host - invalid upgrade",
   238  			method:          "GET",
   239  			upgradeRequired: true,
   240  			requestHeader: map[string]string{
   241  				httpstream.HeaderConnection: httpstream.HeaderUpgrade,
   242  			},
   243  			expectError: func(err error) bool {
   244  				return err != nil && strings.Contains(err.Error(), "invalid upgrade response: status code 200")
   245  			},
   246  			requestPath:     "/some/path",
   247  			expectedPath:    "/some/path",
   248  			useLocationHost: true,
   249  		},
   250  		{
   251  			name:               "append server path to request path",
   252  			method:             "GET",
   253  			requestPath:        "/base",
   254  			expectedPath:       "/base/base",
   255  			appendLocationPath: true,
   256  		},
   257  		{
   258  			name:               "append server path to request path with ending slash",
   259  			method:             "GET",
   260  			requestPath:        "/base/",
   261  			expectedPath:       "/base/base/",
   262  			appendLocationPath: true,
   263  		},
   264  		{
   265  			name:               "don't append server path to request path",
   266  			method:             "GET",
   267  			requestPath:        "/base",
   268  			expectedPath:       "/base",
   269  			appendLocationPath: false,
   270  		},
   271  	}
   272  
   273  	for i, test := range tests {
   274  		func() {
   275  			backendResponse := "<html><head></head><body><a href=\"/test/path\">Hello</a></body></html>"
   276  			backendResponseHeader := test.responseHeader
   277  			// Test a simple header if not specified in the test
   278  			if backendResponseHeader == nil && test.expectedRespHeader == nil {
   279  				backendResponseHeader = map[string]string{"Content-Type": "text/html"}
   280  				test.expectedRespHeader = map[string]string{"Content-Type": "text/html"}
   281  			}
   282  			backendHandler := &SimpleBackendHandler{
   283  				responseBody:   backendResponse,
   284  				responseHeader: backendResponseHeader,
   285  			}
   286  			backendServer := httptest.NewServer(backendHandler)
   287  			defer backendServer.Close()
   288  
   289  			responder := &fakeResponder{t: t}
   290  			backendURL, _ := url.Parse(backendServer.URL)
   291  			backendURL.Path = test.requestPath
   292  			proxyHandler := NewUpgradeAwareHandler(backendURL, nil, false, test.upgradeRequired, responder)
   293  			proxyHandler.UseLocationHost = test.useLocationHost
   294  			proxyHandler.AppendLocationPath = test.appendLocationPath
   295  			proxyServer := httptest.NewServer(proxyHandler)
   296  			defer proxyServer.Close()
   297  			proxyURL, _ := url.Parse(proxyServer.URL)
   298  			proxyURL.Path = test.requestPath
   299  			paramValues := url.Values{}
   300  			for k, v := range test.requestParams {
   301  				paramValues[k] = []string{v}
   302  			}
   303  			proxyURL.RawQuery = paramValues.Encode()
   304  			var requestBody io.Reader
   305  			if test.requestBody != "" {
   306  				requestBody = bytes.NewBufferString(test.requestBody)
   307  			}
   308  			req, err := http.NewRequest(test.method, proxyURL.String(), requestBody)
   309  			if test.requestHeader != nil {
   310  				header := http.Header{}
   311  				for k, v := range test.requestHeader {
   312  					header.Add(k, v)
   313  				}
   314  				req.Header = header
   315  			}
   316  			if err != nil {
   317  				t.Errorf("Error creating client request: %v", err)
   318  			}
   319  			client := &http.Client{}
   320  			res, err := client.Do(req)
   321  			if err != nil {
   322  				t.Errorf("Error from proxy request: %v", err)
   323  			}
   324  
   325  			// Host
   326  			if test.useLocationHost && backendHandler.requestHost != backendURL.Host {
   327  				t.Errorf("Unexpected request host: %s", backendHandler.requestHost)
   328  			} else if !test.useLocationHost && backendHandler.requestHost == backendURL.Host {
   329  				t.Errorf("Unexpected request host: %s", backendHandler.requestHost)
   330  			}
   331  
   332  			if test.expectError != nil {
   333  				if !responder.called {
   334  					t.Errorf("%d: responder was not invoked", i)
   335  					return
   336  				}
   337  				if !test.expectError(responder.err) {
   338  					t.Errorf("%d: unexpected error: %v", i, responder.err)
   339  				}
   340  				return
   341  			}
   342  
   343  			// Validate backend request
   344  			// Method
   345  			if backendHandler.requestMethod != test.method {
   346  				t.Errorf("Unexpected request method: %s. Expected: %s",
   347  					backendHandler.requestMethod, test.method)
   348  			}
   349  
   350  			// Body
   351  			if string(backendHandler.requestBody) != test.requestBody {
   352  				t.Errorf("Unexpected request body: %s. Expected: %s",
   353  					string(backendHandler.requestBody), test.requestBody)
   354  			}
   355  
   356  			// Path
   357  			if backendHandler.requestURL.Path != test.expectedPath {
   358  				t.Errorf("Unexpected request path: %s", backendHandler.requestURL.Path)
   359  			}
   360  			// Parameters
   361  			validateParameters(t, test.name, backendHandler.requestURL.Query(), test.requestParams)
   362  
   363  			// Headers
   364  			validateHeaders(t, test.name+" backend request", backendHandler.requestHeader,
   365  				test.requestHeader, nil)
   366  
   367  			// Validate proxy response
   368  
   369  			// Response Headers
   370  			validateHeaders(t, test.name+" backend headers", res.Header, test.expectedRespHeader, test.notExpectedRespHeader)
   371  
   372  			// Validate Body
   373  			responseBody, err := ioutil.ReadAll(res.Body)
   374  			if err != nil {
   375  				t.Errorf("Unexpected error reading response body: %v", err)
   376  			}
   377  			if rb := string(responseBody); rb != backendResponse {
   378  				t.Errorf("Did not get expected response body: %s. Expected: %s", rb, backendResponse)
   379  			}
   380  
   381  			// Error
   382  			if responder.called {
   383  				t.Errorf("Unexpected proxy handler error: %v", responder.err)
   384  			}
   385  		}()
   386  	}
   387  }
   388  
   389  type RoundTripperFunc func(req *http.Request) (*http.Response, error)
   390  
   391  func (fn RoundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) {
   392  	return fn(req)
   393  }
   394  
   395  func TestProxyUpgrade(t *testing.T) {
   396  
   397  	localhostPool := x509.NewCertPool()
   398  	if !localhostPool.AppendCertsFromPEM(localhostCert) {
   399  		t.Errorf("error setting up localhostCert pool")
   400  	}
   401  	var d net.Dialer
   402  
   403  	testcases := map[string]struct {
   404  		ServerFunc       func(http.Handler) *httptest.Server
   405  		ProxyTransport   http.RoundTripper
   406  		UpgradeTransport UpgradeRequestRoundTripper
   407  		ExpectedAuth     string
   408  	}{
   409  		"http": {
   410  			ServerFunc:     httptest.NewServer,
   411  			ProxyTransport: nil,
   412  		},
   413  		"both client and server support http2, but force to http/1.1 for upgrade": {
   414  			ServerFunc: func(h http.Handler) *httptest.Server {
   415  				cert, err := tls.X509KeyPair(exampleCert, exampleKey)
   416  				if err != nil {
   417  					t.Errorf("https (invalid hostname): proxy_test: %v", err)
   418  				}
   419  				ts := httptest.NewUnstartedServer(h)
   420  				ts.TLS = &tls.Config{
   421  					Certificates: []tls.Certificate{cert},
   422  					NextProtos:   []string{"http2", "http/1.1"},
   423  				}
   424  				ts.StartTLS()
   425  				return ts
   426  			},
   427  			ProxyTransport: utilnet.SetTransportDefaults(&http.Transport{TLSClientConfig: &tls.Config{
   428  				NextProtos:         []string{"http2", "http/1.1"},
   429  				InsecureSkipVerify: true,
   430  			}}),
   431  		},
   432  		"https (invalid hostname + InsecureSkipVerify)": {
   433  			ServerFunc: func(h http.Handler) *httptest.Server {
   434  				cert, err := tls.X509KeyPair(exampleCert, exampleKey)
   435  				if err != nil {
   436  					t.Errorf("https (invalid hostname): proxy_test: %v", err)
   437  				}
   438  				ts := httptest.NewUnstartedServer(h)
   439  				ts.TLS = &tls.Config{
   440  					Certificates: []tls.Certificate{cert},
   441  				}
   442  				ts.StartTLS()
   443  				return ts
   444  			},
   445  			ProxyTransport: utilnet.SetTransportDefaults(&http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}),
   446  		},
   447  		"https (valid hostname + RootCAs)": {
   448  			ServerFunc: func(h http.Handler) *httptest.Server {
   449  				cert, err := tls.X509KeyPair(localhostCert, localhostKey)
   450  				if err != nil {
   451  					t.Errorf("https (valid hostname): proxy_test: %v", err)
   452  				}
   453  				ts := httptest.NewUnstartedServer(h)
   454  				ts.TLS = &tls.Config{
   455  					Certificates: []tls.Certificate{cert},
   456  				}
   457  				ts.StartTLS()
   458  				return ts
   459  			},
   460  			ProxyTransport: utilnet.SetTransportDefaults(&http.Transport{TLSClientConfig: &tls.Config{RootCAs: localhostPool}}),
   461  		},
   462  		"https (valid hostname + RootCAs + custom dialer)": {
   463  			ServerFunc: func(h http.Handler) *httptest.Server {
   464  				cert, err := tls.X509KeyPair(localhostCert, localhostKey)
   465  				if err != nil {
   466  					t.Errorf("https (valid hostname): proxy_test: %v", err)
   467  				}
   468  				ts := httptest.NewUnstartedServer(h)
   469  				ts.TLS = &tls.Config{
   470  					Certificates: []tls.Certificate{cert},
   471  				}
   472  				ts.StartTLS()
   473  				return ts
   474  			},
   475  			ProxyTransport: utilnet.SetTransportDefaults(&http.Transport{DialContext: d.DialContext, TLSClientConfig: &tls.Config{RootCAs: localhostPool}}),
   476  		},
   477  		"https (valid hostname + RootCAs + custom dialer + bearer token)": {
   478  			ServerFunc: func(h http.Handler) *httptest.Server {
   479  				cert, err := tls.X509KeyPair(localhostCert, localhostKey)
   480  				if err != nil {
   481  					t.Errorf("https (valid hostname): proxy_test: %v", err)
   482  				}
   483  				ts := httptest.NewUnstartedServer(h)
   484  				ts.TLS = &tls.Config{
   485  					Certificates: []tls.Certificate{cert},
   486  				}
   487  				ts.StartTLS()
   488  				return ts
   489  			},
   490  			ProxyTransport: utilnet.SetTransportDefaults(&http.Transport{DialContext: d.DialContext, TLSClientConfig: &tls.Config{RootCAs: localhostPool}}),
   491  			UpgradeTransport: NewUpgradeRequestRoundTripper(
   492  				utilnet.SetOldTransportDefaults(&http.Transport{DialContext: d.DialContext, TLSClientConfig: &tls.Config{RootCAs: localhostPool}}),
   493  				RoundTripperFunc(func(req *http.Request) (*http.Response, error) {
   494  					req = utilnet.CloneRequest(req)
   495  					req.Header.Set("Authorization", "Bearer 1234")
   496  					return MirrorRequest.RoundTrip(req)
   497  				}),
   498  			),
   499  			ExpectedAuth: "Bearer 1234",
   500  		},
   501  	}
   502  
   503  	for k, tc := range testcases {
   504  		tcName := k
   505  		backendPath := "/hello"
   506  		func() { // Cleanup after each test case.
   507  			backend := http.NewServeMux()
   508  			backend.Handle("/hello", websocket.Handler(func(ws *websocket.Conn) {
   509  				if ws.Request().Header.Get("Authorization") != tc.ExpectedAuth {
   510  					t.Errorf("%s: unexpected headers on request: %v", k, ws.Request().Header)
   511  					defer ws.Close()
   512  					ws.Write([]byte("you failed"))
   513  					return
   514  				}
   515  				defer ws.Close()
   516  				body := make([]byte, 5)
   517  				ws.Read(body)
   518  				ws.Write([]byte("hello " + string(body)))
   519  			}))
   520  			backend.Handle("/redirect", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   521  				http.Redirect(w, r, "/hello", http.StatusFound)
   522  			}))
   523  			backendServer := tc.ServerFunc(backend)
   524  			defer backendServer.Close()
   525  
   526  			serverURL, _ := url.Parse(backendServer.URL)
   527  			serverURL.Path = backendPath
   528  			proxyHandler := NewUpgradeAwareHandler(serverURL, tc.ProxyTransport, false, false, &noErrorsAllowed{t: t})
   529  			proxyHandler.UpgradeTransport = tc.UpgradeTransport
   530  			proxy := httptest.NewServer(proxyHandler)
   531  			defer proxy.Close()
   532  
   533  			ws, err := websocket.Dial("ws://"+proxy.Listener.Addr().String()+"/some/path", "", "http://127.0.0.1/")
   534  			if err != nil {
   535  				t.Fatalf("%s: websocket dial err: %s", tcName, err)
   536  			}
   537  			defer ws.Close()
   538  
   539  			if _, err := ws.Write([]byte("world")); err != nil {
   540  				t.Fatalf("%s: write err: %s", tcName, err)
   541  			}
   542  
   543  			response := make([]byte, 20)
   544  			n, err := ws.Read(response)
   545  			if err != nil {
   546  				t.Fatalf("%s: read err: %s", tcName, err)
   547  			}
   548  			if e, a := "hello world", string(response[0:n]); e != a {
   549  				t.Fatalf("%s: expected '%#v', got '%#v'", tcName, e, a)
   550  			}
   551  		}()
   552  	}
   553  }
   554  
   555  type noErrorsAllowed struct {
   556  	t *testing.T
   557  }
   558  
   559  func (r *noErrorsAllowed) Error(w http.ResponseWriter, req *http.Request, err error) {
   560  	r.t.Error(err)
   561  }
   562  
   563  func TestProxyUpgradeConnectionErrorResponse(t *testing.T) {
   564  	var (
   565  		responder   *fakeResponder
   566  		expectedErr = errors.New("EXPECTED")
   567  	)
   568  	proxy := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   569  		transport := &http.Transport{
   570  			Proxy: http.ProxyFromEnvironment,
   571  			DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
   572  				return &fakeConn{err: expectedErr}, nil
   573  			},
   574  			MaxIdleConns:          100,
   575  			IdleConnTimeout:       90 * time.Second,
   576  			TLSHandshakeTimeout:   10 * time.Second,
   577  			ExpectContinueTimeout: 1 * time.Second,
   578  		}
   579  		responder = &fakeResponder{t: t, w: w}
   580  		proxyHandler := NewUpgradeAwareHandler(
   581  			&url.URL{
   582  				Host: "fake-backend",
   583  			},
   584  			transport,
   585  			false,
   586  			true,
   587  			responder,
   588  		)
   589  		proxyHandler.ServeHTTP(w, r)
   590  	}))
   591  	defer proxy.Close()
   592  
   593  	// Send request to proxy server.
   594  	req, err := http.NewRequest("POST", "http://"+proxy.Listener.Addr().String()+"/some/path", nil)
   595  	require.NoError(t, err)
   596  	req.Header.Set(httpstream.HeaderConnection, httpstream.HeaderUpgrade)
   597  	resp, err := http.DefaultClient.Do(req)
   598  	require.NoError(t, err)
   599  	defer resp.Body.Close()
   600  
   601  	// Expect error response.
   602  	assert.True(t, responder.called)
   603  	assert.Equal(t, fakeStatusCode, resp.StatusCode)
   604  	msg, err := ioutil.ReadAll(resp.Body)
   605  	require.NoError(t, err)
   606  	assert.Contains(t, string(msg), expectedErr.Error())
   607  }
   608  
   609  func TestProxyUpgradeErrorResponseTerminates(t *testing.T) {
   610  	for _, code := range []int{400, 500} {
   611  		t.Run(fmt.Sprintf("code=%v", code), func(t *testing.T) {
   612  			// Set up a backend server
   613  			backend := http.NewServeMux()
   614  			backend.Handle("/hello", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   615  				w.WriteHeader(code)
   616  				w.Write([]byte(`some data`))
   617  			}))
   618  			backend.Handle("/there", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   619  				t.Error("request to /there")
   620  			}))
   621  			backendServer := httptest.NewServer(backend)
   622  			defer backendServer.Close()
   623  			backendServerURL, _ := url.Parse(backendServer.URL)
   624  			backendServerURL.Path = "/hello"
   625  
   626  			// Set up a proxy pointing to a specific path on the backend
   627  			proxyHandler := NewUpgradeAwareHandler(backendServerURL, nil, false, false, &noErrorsAllowed{t: t})
   628  			proxy := httptest.NewServer(proxyHandler)
   629  			defer proxy.Close()
   630  			proxyURL, _ := url.Parse(proxy.URL)
   631  
   632  			conn, err := net.Dial("tcp", proxyURL.Host)
   633  			require.NoError(t, err)
   634  			bufferedReader := bufio.NewReader(conn)
   635  
   636  			// Send upgrade request resulting in a non-101 response from the backend
   637  			req, _ := http.NewRequest("GET", "/", nil)
   638  			req.Header.Set(httpstream.HeaderConnection, httpstream.HeaderUpgrade)
   639  			require.NoError(t, req.Write(conn))
   640  			// Verify we get the correct response and full message body content
   641  			resp, err := http.ReadResponse(bufferedReader, nil)
   642  			require.NoError(t, err)
   643  			data, err := ioutil.ReadAll(resp.Body)
   644  			require.NoError(t, err)
   645  			require.Equal(t, resp.StatusCode, code)
   646  			require.Equal(t, data, []byte(`some data`))
   647  			resp.Body.Close()
   648  
   649  			// try to read from the connection to verify it was closed
   650  			b := make([]byte, 1)
   651  			conn.SetReadDeadline(time.Now().Add(time.Second))
   652  			if _, err := conn.Read(b); err != io.EOF {
   653  				t.Errorf("expected EOF, got %v", err)
   654  			}
   655  
   656  			// Send another request to another endpoint to verify it is not received
   657  			req, _ = http.NewRequest("GET", "/there", nil)
   658  			req.Write(conn)
   659  			// wait to ensure the handler does not receive the request
   660  			time.Sleep(time.Second)
   661  
   662  			// clean up
   663  			conn.Close()
   664  		})
   665  	}
   666  }
   667  
   668  func TestProxyUpgradeErrorResponse(t *testing.T) {
   669  	for _, code := range []int{200, 300, 302, 307} {
   670  		t.Run(fmt.Sprintf("code=%v", code), func(t *testing.T) {
   671  			// Set up a backend server
   672  			backend := http.NewServeMux()
   673  			backend.Handle("/hello", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   674  				http.Redirect(w, r, "https://example.com/there", code)
   675  			}))
   676  			backendServer := httptest.NewServer(backend)
   677  			defer backendServer.Close()
   678  			backendServerURL, _ := url.Parse(backendServer.URL)
   679  			backendServerURL.Path = "/hello"
   680  
   681  			// Set up a proxy pointing to a specific path on the backend
   682  			proxyHandler := NewUpgradeAwareHandler(backendServerURL, nil, false, false, &fakeResponder{t: t})
   683  			proxy := httptest.NewServer(proxyHandler)
   684  			defer proxy.Close()
   685  			proxyURL, _ := url.Parse(proxy.URL)
   686  
   687  			conn, err := net.Dial("tcp", proxyURL.Host)
   688  			require.NoError(t, err)
   689  			bufferedReader := bufio.NewReader(conn)
   690  
   691  			// Send upgrade request resulting in a non-101 response from the backend
   692  			req, _ := http.NewRequest("GET", "/", nil)
   693  			req.Header.Set(httpstream.HeaderConnection, httpstream.HeaderUpgrade)
   694  			require.NoError(t, req.Write(conn))
   695  			// Verify we get the correct response and full message body content
   696  			resp, err := http.ReadResponse(bufferedReader, nil)
   697  			require.NoError(t, err)
   698  			assert.Equal(t, fakeStatusCode, resp.StatusCode)
   699  			resp.Body.Close()
   700  
   701  			// clean up
   702  			conn.Close()
   703  		})
   704  	}
   705  }
   706  
   707  func TestRejectForwardingRedirectsOption(t *testing.T) {
   708  	originalBody := []byte(`some data`)
   709  	testCases := []struct {
   710  		name                      string
   711  		rejectForwardingRedirects bool
   712  		serverStatusCode          int
   713  		redirect                  string
   714  		expectStatusCode          int
   715  		expectBody                []byte
   716  	}{
   717  		{
   718  			name:                      "reject redirection enabled in proxy, backend server sending 200 response",
   719  			rejectForwardingRedirects: true,
   720  			serverStatusCode:          200,
   721  			expectStatusCode:          200,
   722  			expectBody:                originalBody,
   723  		},
   724  		{
   725  			name:                      "reject redirection enabled in proxy, backend server sending 301 response",
   726  			rejectForwardingRedirects: true,
   727  			serverStatusCode:          301,
   728  			redirect:                  "/",
   729  			expectStatusCode:          502,
   730  			expectBody:                []byte(`the backend attempted to redirect this request, which is not permitted`),
   731  		},
   732  		{
   733  			name:                      "reject redirection enabled in proxy, backend server sending 304 response with a location header",
   734  			rejectForwardingRedirects: true,
   735  			serverStatusCode:          304,
   736  			redirect:                  "/",
   737  			expectStatusCode:          502,
   738  			expectBody:                []byte(`the backend attempted to redirect this request, which is not permitted`),
   739  		},
   740  		{
   741  			name:                      "reject redirection enabled in proxy, backend server sending 304 response with no location header",
   742  			rejectForwardingRedirects: true,
   743  			serverStatusCode:          304,
   744  			expectStatusCode:          304,
   745  			expectBody:                []byte{}, // client doesn't read the body for 304 responses
   746  		},
   747  		{
   748  			name:                      "reject redirection disabled in proxy, backend server sending 200 response",
   749  			rejectForwardingRedirects: false,
   750  			serverStatusCode:          200,
   751  			expectStatusCode:          200,
   752  			expectBody:                originalBody,
   753  		},
   754  		{
   755  			name:                      "reject redirection disabled in proxy, backend server sending 301 response",
   756  			rejectForwardingRedirects: false,
   757  			serverStatusCode:          301,
   758  			redirect:                  "/",
   759  			expectStatusCode:          301,
   760  			expectBody:                originalBody,
   761  		},
   762  	}
   763  	for _, tc := range testCases {
   764  		t.Run(tc.name, func(t *testing.T) {
   765  			// Set up a backend server
   766  			backendServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   767  				if tc.redirect != "" {
   768  					w.Header().Set("Location", tc.redirect)
   769  				}
   770  				w.WriteHeader(tc.serverStatusCode)
   771  				w.Write(originalBody)
   772  			}))
   773  			defer backendServer.Close()
   774  			backendServerURL, _ := url.Parse(backendServer.URL)
   775  
   776  			// Set up a proxy pointing to the backend
   777  			proxyHandler := NewUpgradeAwareHandler(backendServerURL, nil, false, false, &fakeResponder{t: t})
   778  			proxyHandler.RejectForwardingRedirects = tc.rejectForwardingRedirects
   779  			proxy := httptest.NewServer(proxyHandler)
   780  			defer proxy.Close()
   781  			proxyURL, _ := url.Parse(proxy.URL)
   782  
   783  			conn, err := net.Dial("tcp", proxyURL.Host)
   784  			require.NoError(t, err)
   785  			bufferedReader := bufio.NewReader(conn)
   786  
   787  			req, _ := http.NewRequest("GET", proxyURL.String(), nil)
   788  			require.NoError(t, req.Write(conn))
   789  			// Verify we get the correct response and message body content
   790  			resp, err := http.ReadResponse(bufferedReader, nil)
   791  			require.NoError(t, err)
   792  			assert.Equal(t, tc.expectStatusCode, resp.StatusCode)
   793  			data, err := ioutil.ReadAll(resp.Body)
   794  			require.NoError(t, err)
   795  			assert.Equal(t, tc.expectBody, data)
   796  			assert.Equal(t, int64(len(tc.expectBody)), resp.ContentLength)
   797  			resp.Body.Close()
   798  
   799  			// clean up
   800  			conn.Close()
   801  		})
   802  	}
   803  }
   804  
   805  func TestDefaultProxyTransport(t *testing.T) {
   806  	tests := []struct {
   807  		name,
   808  		url,
   809  		location,
   810  		expectedScheme,
   811  		expectedHost,
   812  		expectedPathPrepend string
   813  	}{
   814  		{
   815  			name:                "simple path",
   816  			url:                 "http://test.server:8080/a/test/location",
   817  			location:            "http://localhost/location",
   818  			expectedScheme:      "http",
   819  			expectedHost:        "test.server:8080",
   820  			expectedPathPrepend: "/a/test",
   821  		},
   822  		{
   823  			name:                "empty path",
   824  			url:                 "http://test.server:8080/a/test/",
   825  			location:            "http://localhost",
   826  			expectedScheme:      "http",
   827  			expectedHost:        "test.server:8080",
   828  			expectedPathPrepend: "/a/test",
   829  		},
   830  		{
   831  			name:                "location ending in slash",
   832  			url:                 "http://test.server:8080/a/test/",
   833  			location:            "http://localhost/",
   834  			expectedScheme:      "http",
   835  			expectedHost:        "test.server:8080",
   836  			expectedPathPrepend: "/a/test",
   837  		},
   838  	}
   839  
   840  	for _, test := range tests {
   841  		locURL, _ := url.Parse(test.location)
   842  		URL, _ := url.Parse(test.url)
   843  		h := NewUpgradeAwareHandler(locURL, nil, false, false, nil)
   844  		result := h.defaultProxyTransport(URL, nil)
   845  		transport := result.(*corsRemovingTransport).RoundTripper.(*Transport)
   846  		if transport.Scheme != test.expectedScheme {
   847  			t.Errorf("%s: unexpected scheme. Actual: %s, Expected: %s", test.name, transport.Scheme, test.expectedScheme)
   848  		}
   849  		if transport.Host != test.expectedHost {
   850  			t.Errorf("%s: unexpected host. Actual: %s, Expected: %s", test.name, transport.Host, test.expectedHost)
   851  		}
   852  		if transport.PathPrepend != test.expectedPathPrepend {
   853  			t.Errorf("%s: unexpected path prepend. Actual: %s, Expected: %s", test.name, transport.PathPrepend, test.expectedPathPrepend)
   854  		}
   855  	}
   856  }
   857  
   858  func TestProxyRequestContentLengthAndTransferEncoding(t *testing.T) {
   859  	chunk := func(data []byte) []byte {
   860  		out := &bytes.Buffer{}
   861  		chunker := httputil.NewChunkedWriter(out)
   862  		for _, b := range data {
   863  			if _, err := chunker.Write([]byte{b}); err != nil {
   864  				panic(err)
   865  			}
   866  		}
   867  		chunker.Close()
   868  		out.Write([]byte("\r\n"))
   869  		return out.Bytes()
   870  	}
   871  
   872  	zip := func(data []byte) []byte {
   873  		out := &bytes.Buffer{}
   874  		zipper := gzip.NewWriter(out)
   875  		if _, err := zipper.Write(data); err != nil {
   876  			panic(err)
   877  		}
   878  		zipper.Close()
   879  		return out.Bytes()
   880  	}
   881  
   882  	sampleData := []byte("abcde")
   883  
   884  	table := map[string]struct {
   885  		reqHeaders http.Header
   886  		reqBody    []byte
   887  
   888  		expectedHeaders http.Header
   889  		expectedBody    []byte
   890  	}{
   891  		"content-length": {
   892  			reqHeaders: http.Header{
   893  				"Content-Length": []string{"5"},
   894  			},
   895  			reqBody: sampleData,
   896  
   897  			expectedHeaders: http.Header{
   898  				"Content-Length":    []string{"5"},
   899  				"Content-Encoding":  nil, // none set
   900  				"Transfer-Encoding": nil, // none set
   901  			},
   902  			expectedBody: sampleData,
   903  		},
   904  
   905  		"content-length + gzip content-encoding": {
   906  			reqHeaders: http.Header{
   907  				"Content-Length":   []string{strconv.Itoa(len(zip(sampleData)))},
   908  				"Content-Encoding": []string{"gzip"},
   909  			},
   910  			reqBody: zip(sampleData),
   911  
   912  			expectedHeaders: http.Header{
   913  				"Content-Length":    []string{strconv.Itoa(len(zip(sampleData)))},
   914  				"Content-Encoding":  []string{"gzip"},
   915  				"Transfer-Encoding": nil, // none set
   916  			},
   917  			expectedBody: zip(sampleData),
   918  		},
   919  
   920  		"chunked transfer-encoding": {
   921  			reqHeaders: http.Header{
   922  				"Transfer-Encoding": []string{"chunked"},
   923  			},
   924  			reqBody: chunk(sampleData),
   925  
   926  			expectedHeaders: http.Header{
   927  				"Content-Length":    nil, // none set
   928  				"Content-Encoding":  nil, // none set
   929  				"Transfer-Encoding": nil, // Transfer-Encoding gets removed
   930  			},
   931  			expectedBody: sampleData, // sample data is unchunked
   932  		},
   933  
   934  		"chunked transfer-encoding + gzip content-encoding": {
   935  			reqHeaders: http.Header{
   936  				"Content-Encoding":  []string{"gzip"},
   937  				"Transfer-Encoding": []string{"chunked"},
   938  			},
   939  			reqBody: chunk(zip(sampleData)),
   940  
   941  			expectedHeaders: http.Header{
   942  				"Content-Length":    nil, // none set
   943  				"Content-Encoding":  []string{"gzip"},
   944  				"Transfer-Encoding": nil, // gets removed
   945  			},
   946  			expectedBody: zip(sampleData), // sample data is unchunked, but content-encoding is preserved
   947  		},
   948  
   949  		// "Transfer-Encoding: gzip" is not supported by go
   950  		// See http/transfer.go#fixTransferEncoding (https://golang.org/src/net/http/transfer.go#L427)
   951  		// Once it is supported, this test case should succeed
   952  		//
   953  		// "gzip+chunked transfer-encoding": {
   954  		// 	reqHeaders: http.Header{
   955  		// 		"Transfer-Encoding": []string{"chunked,gzip"},
   956  		// 	},
   957  		// 	reqBody: chunk(zip(sampleData)),
   958  		//
   959  		// 	expectedHeaders: http.Header{
   960  		// 		"Content-Length":    nil, // no content-length headers
   961  		// 		"Transfer-Encoding": nil, // Transfer-Encoding gets removed
   962  		// 	},
   963  		// 	expectedBody: sampleData,
   964  		// },
   965  	}
   966  
   967  	successfulResponse := "backend passed tests"
   968  	for k, item := range table {
   969  		// Start the downstream server
   970  		downstreamServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
   971  			// Verify headers
   972  			for header, v := range item.expectedHeaders {
   973  				if !reflect.DeepEqual(v, req.Header[header]) {
   974  					t.Errorf("%s: Expected headers for %s to be %v, got %v", k, header, v, req.Header[header])
   975  				}
   976  			}
   977  
   978  			// Read body
   979  			body, err := ioutil.ReadAll(req.Body)
   980  			if err != nil {
   981  				t.Errorf("%s: unexpected error %v", k, err)
   982  			}
   983  			req.Body.Close()
   984  
   985  			// Verify length
   986  			if req.ContentLength > 0 && req.ContentLength != int64(len(body)) {
   987  				t.Errorf("%s: ContentLength was %d, len(data) was %d", k, req.ContentLength, len(body))
   988  			}
   989  
   990  			// Verify content
   991  			if !bytes.Equal(item.expectedBody, body) {
   992  				t.Errorf("%s: Expected %q, got %q", k, string(item.expectedBody), string(body))
   993  			}
   994  
   995  			// Write successful response
   996  			w.Write([]byte(successfulResponse))
   997  		}))
   998  		defer downstreamServer.Close()
   999  
  1000  		responder := &fakeResponder{t: t}
  1001  		backendURL, _ := url.Parse(downstreamServer.URL)
  1002  		proxyHandler := NewUpgradeAwareHandler(backendURL, nil, false, false, responder)
  1003  		proxyServer := httptest.NewServer(proxyHandler)
  1004  		defer proxyServer.Close()
  1005  
  1006  		// Dial the proxy server
  1007  		conn, err := net.Dial(proxyServer.Listener.Addr().Network(), proxyServer.Listener.Addr().String())
  1008  		if err != nil {
  1009  			t.Errorf("unexpected error %v", err)
  1010  			continue
  1011  		}
  1012  		defer conn.Close()
  1013  
  1014  		// Add standard http 1.1 headers
  1015  		if item.reqHeaders == nil {
  1016  			item.reqHeaders = http.Header{}
  1017  		}
  1018  		item.reqHeaders.Add("Connection", "close")
  1019  		item.reqHeaders.Add("Host", proxyServer.Listener.Addr().String())
  1020  
  1021  		// Write the request headers
  1022  		if _, err := fmt.Fprint(conn, "POST / HTTP/1.1\r\n"); err != nil {
  1023  			t.Fatalf("%s unexpected error %v", k, err)
  1024  		}
  1025  		for header, values := range item.reqHeaders {
  1026  			for _, value := range values {
  1027  				if _, err := fmt.Fprintf(conn, "%s: %s\r\n", header, value); err != nil {
  1028  					t.Fatalf("%s: unexpected error %v", k, err)
  1029  				}
  1030  			}
  1031  		}
  1032  		// Header separator
  1033  		if _, err := fmt.Fprint(conn, "\r\n"); err != nil {
  1034  			t.Fatalf("%s: unexpected error %v", k, err)
  1035  		}
  1036  		// Body
  1037  		if _, err := conn.Write(item.reqBody); err != nil {
  1038  			t.Fatalf("%s: unexpected error %v", k, err)
  1039  		}
  1040  
  1041  		// Read response
  1042  		response, err := ioutil.ReadAll(conn)
  1043  		if err != nil {
  1044  			t.Errorf("%s: unexpected error %v", k, err)
  1045  			continue
  1046  		}
  1047  		if !strings.HasSuffix(string(response), successfulResponse) {
  1048  			t.Errorf("%s: Did not get successful response: %s", k, string(response))
  1049  			continue
  1050  		}
  1051  	}
  1052  }
  1053  
  1054  func TestFlushIntervalHeaders(t *testing.T) {
  1055  	const expected = "hi"
  1056  	stopCh := make(chan struct{})
  1057  	backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1058  		w.Header().Add("MyHeader", expected)
  1059  		w.WriteHeader(200)
  1060  		w.(http.Flusher).Flush()
  1061  		<-stopCh
  1062  	}))
  1063  	defer backend.Close()
  1064  	defer close(stopCh)
  1065  
  1066  	backendURL, err := url.Parse(backend.URL)
  1067  	if err != nil {
  1068  		t.Fatal(err)
  1069  	}
  1070  
  1071  	responder := &fakeResponder{t: t}
  1072  	proxyHandler := NewUpgradeAwareHandler(backendURL, nil, false, false, responder)
  1073  
  1074  	frontend := httptest.NewServer(proxyHandler)
  1075  	defer frontend.Close()
  1076  
  1077  	req, _ := http.NewRequest("GET", frontend.URL, nil)
  1078  	req.Close = true
  1079  
  1080  	ctx, cancel := context.WithTimeout(req.Context(), 10*time.Second)
  1081  	defer cancel()
  1082  	req = req.WithContext(ctx)
  1083  
  1084  	res, err := frontend.Client().Do(req)
  1085  	if err != nil {
  1086  		t.Fatalf("Get: %v", err)
  1087  	}
  1088  	defer res.Body.Close()
  1089  
  1090  	if res.Header.Get("MyHeader") != expected {
  1091  		t.Errorf("got header %q; expected %q", res.Header.Get("MyHeader"), expected)
  1092  	}
  1093  }
  1094  
  1095  type fakeRT struct {
  1096  	err error
  1097  }
  1098  
  1099  func (frt *fakeRT) RoundTrip(*http.Request) (*http.Response, error) {
  1100  	return nil, frt.err
  1101  }
  1102  
  1103  // TestErrorPropagation checks if the default transport doesn't swallow the errors by providing a fakeResponder that intercepts and stores the error.
  1104  func TestErrorPropagation(t *testing.T) {
  1105  	backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1106  		panic("unreachable")
  1107  	}))
  1108  	defer backend.Close()
  1109  
  1110  	backendURL, err := url.Parse(backend.URL)
  1111  	if err != nil {
  1112  		t.Fatal(err)
  1113  	}
  1114  
  1115  	responder := &fakeResponder{t: t}
  1116  	expectedErr := errors.New("nasty error")
  1117  	proxyHandler := NewUpgradeAwareHandler(backendURL, &fakeRT{err: expectedErr}, true, false, responder)
  1118  
  1119  	frontend := httptest.NewServer(proxyHandler)
  1120  	defer frontend.Close()
  1121  
  1122  	req, _ := http.NewRequest("GET", frontend.URL, nil)
  1123  	req.Close = true
  1124  
  1125  	ctx, cancel := context.WithTimeout(req.Context(), 10*time.Second)
  1126  	defer cancel()
  1127  	req = req.WithContext(ctx)
  1128  
  1129  	res, err := frontend.Client().Do(req)
  1130  	if err != nil {
  1131  		t.Fatalf("Get: %v", err)
  1132  	}
  1133  	defer res.Body.Close()
  1134  	if res.StatusCode != fakeStatusCode {
  1135  		t.Fatalf("unexpected HTTP status code returned: %v, expected: %v", res.StatusCode, fakeStatusCode)
  1136  	}
  1137  	if !strings.Contains(responder.err.Error(), expectedErr.Error()) {
  1138  		t.Fatalf("responder got unexpected error: %v, expected the error to contain %q", responder.err.Error(), expectedErr.Error())
  1139  	}
  1140  }
  1141  
  1142  func TestProxyRedirectsforRootPath(t *testing.T) {
  1143  
  1144  	tests := []struct {
  1145  		name               string
  1146  		method             string
  1147  		requestPath        string
  1148  		expectedHeader     http.Header
  1149  		expectedStatusCode int
  1150  		redirect           bool
  1151  	}{
  1152  		{
  1153  			name:               "root path, simple get",
  1154  			method:             "GET",
  1155  			requestPath:        "",
  1156  			redirect:           true,
  1157  			expectedStatusCode: 301,
  1158  			expectedHeader: http.Header{
  1159  				"Location": []string{"/"},
  1160  			},
  1161  		},
  1162  		{
  1163  			name:               "root path, simple put",
  1164  			method:             "PUT",
  1165  			requestPath:        "",
  1166  			redirect:           false,
  1167  			expectedStatusCode: 200,
  1168  		},
  1169  		{
  1170  			name:               "root path, simple head",
  1171  			method:             "HEAD",
  1172  			requestPath:        "",
  1173  			redirect:           true,
  1174  			expectedStatusCode: 301,
  1175  			expectedHeader: http.Header{
  1176  				"Location": []string{"/"},
  1177  			},
  1178  		},
  1179  		{
  1180  			name:               "root path, simple delete with params",
  1181  			method:             "DELETE",
  1182  			requestPath:        "",
  1183  			redirect:           false,
  1184  			expectedStatusCode: 200,
  1185  		},
  1186  	}
  1187  
  1188  	for _, test := range tests {
  1189  		func() {
  1190  			w := httptest.NewRecorder()
  1191  			req, err := http.NewRequest(test.method, test.requestPath, nil)
  1192  			if err != nil {
  1193  				t.Fatal(err)
  1194  			}
  1195  
  1196  			redirect := proxyRedirectsforRootPath(test.requestPath, w, req)
  1197  			if got, want := redirect, test.redirect; got != want {
  1198  				t.Errorf("Expected redirect state %v; got %v", want, got)
  1199  			}
  1200  
  1201  			res := w.Result()
  1202  			if got, want := res.StatusCode, test.expectedStatusCode; got != want {
  1203  				t.Errorf("Expected status code %d; got %d", want, got)
  1204  			}
  1205  
  1206  			if res.StatusCode == 301 && !reflect.DeepEqual(res.Header, test.expectedHeader) {
  1207  				t.Errorf("Expected location header to be %v, got %v", test.expectedHeader, res.Header)
  1208  			}
  1209  		}()
  1210  	}
  1211  }
  1212  
  1213  // exampleCert was generated from crypto/tls/generate_cert.go with the following command:
  1214  //
  1215  //	go run generate_cert.go  --rsa-bits 1024 --host example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
  1216  var exampleCert = []byte(`-----BEGIN CERTIFICATE-----
  1217  MIIDADCCAeigAwIBAgIQVHG3Fn9SdWayyLOZKCW1vzANBgkqhkiG9w0BAQsFADAS
  1218  MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw
  1219  MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
  1220  MIIBCgKCAQEArTCu9fiIclNgDdWHphewM+JW55dCb5yYGlJgCBvwbOx547M9p+tn
  1221  zm9QOhsdZDHDZsG9tqnWxE2Nc1HpIJyOlfYsOoonpEoG/Ep6nnK91ngj0bn/JlNy
  1222  +i/bwU4r97MOukvnOIQez9/D9jAJaOX2+b8/d4lRz9BsqiwJyg+ynZ5tVVYj7aMi
  1223  vXnd6HOnJmtqutOtr3beucJnkd6XbwRkLUcAYATT+ZihOWRbTuKqhCg6zGkJOoUG
  1224  f8sX61JjoilxiURA//ftGVbdTCU3DrmGmardp5NNOHbumMYU8Vhmqgx1Bqxb+9he
  1225  7G42uW5YWYK/GqJzgVPjjlB2dOGj9KrEWQIDAQABo1AwTjAOBgNVHQ8BAf8EBAMC
  1226  AqQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUwAwEB/zAWBgNVHREE
  1227  DzANggtleGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAig4AIi9xWs1+pLES
  1228  eeGGdSDoclplFpcbXANnsYYFyLf+8pcWgVi2bOmb2gXMbHFkB07MA82wRJAUTaA+
  1229  2iNXVQMhPCoA7J6ADUbww9doJX2S9HGyArhiV/MhHtE8txzMn2EKNLdhhk3N9rmV
  1230  x/qRbWAY1U2z4BpdrAR87Fe81Nlj7h45csW9K+eS+NgXipiNTIfEShKgCFM8EdxL
  1231  1WXg7r9AvYV3TNDPWTjLsm1rQzzZQ7Uvcf6deWiNodZd8MOT/BFLclDPTK6cF2Hr
  1232  UU4dq6G4kCwMSxWE4cM3HlZ4u1dyIt47VbkP0rtvkBCXx36y+NXYA5lzntchNFZP
  1233  uvEQdw==
  1234  -----END CERTIFICATE-----`)
  1235  
  1236  var exampleKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
  1237  MIIEpQIBAAKCAQEArTCu9fiIclNgDdWHphewM+JW55dCb5yYGlJgCBvwbOx547M9
  1238  p+tnzm9QOhsdZDHDZsG9tqnWxE2Nc1HpIJyOlfYsOoonpEoG/Ep6nnK91ngj0bn/
  1239  JlNy+i/bwU4r97MOukvnOIQez9/D9jAJaOX2+b8/d4lRz9BsqiwJyg+ynZ5tVVYj
  1240  7aMivXnd6HOnJmtqutOtr3beucJnkd6XbwRkLUcAYATT+ZihOWRbTuKqhCg6zGkJ
  1241  OoUGf8sX61JjoilxiURA//ftGVbdTCU3DrmGmardp5NNOHbumMYU8Vhmqgx1Bqxb
  1242  +9he7G42uW5YWYK/GqJzgVPjjlB2dOGj9KrEWQIDAQABAoIBAQClt4CiYaaF5ltx
  1243  wVDjz6TNcJUBUs3CKE+uWAYFnF5Ii1nyU876Pxj8Aaz9fHZ6Kde0GkwiXY7gFOj1
  1244  YHo2tzcELSKS/SEDZcYbYFTGCjq13g1AH74R+SV6WZLn+5m8kPvVrM1ZWap188H5
  1245  bmuCkRDqVmIvShkbRW7EwhC35J9fiuW3majC/sjmsxtxyP6geWmu4f5/Ttqahcdb
  1246  osPZIgIIPzqAkNtkLTi7+meHYI9wlrGhL7XZTwnJ1Oc/Y67zzmbthLYB5YFSLUew
  1247  rXT58jtSjX4gbiQyheBSrWxW08QE4qYg6jJlAdffHhWv72hJW2MCXhuXp8gJs/Do
  1248  XLRHGwSBAoGBAMdNtsbe4yae/QeHUPGxNW0ipa0yoTF6i+VYoxvqiRMzDM3+3L8k
  1249  dgI1rr4330SivqDahMA/odWtM/9rVwJI2B2QhZLMHA0n9ytH007OO9TghgVB12nN
  1250  xosRYBpKdHXyyvV/MUZl7Jux6zKIzRDWOkF95VVYPcAaxJqd1E5/jJ6JAoGBAN51
  1251  QrebA1w/jfydeqQTz1sK01sbO4HYj4qGfo/JarVqGEkm1azeBBPPRnHz3jNKnCkM
  1252  S4PpqRDased3NIcViXlAgoqPqivZ8mQa/Rb146l7WaTErASHsZ023OGrxsr/Ed6N
  1253  P3GrmvxVJjebaFNaQ9sP80dLkpgeas0t2TY8iQNRAoGATOcnx8TpUVW3vNfx29DN
  1254  FLdxxkrq9/SZVn3FMlhlXAsuva3B799ZybB9JNjaRdmmRNsMrkHfaFvU3JHGmRMS
  1255  kRXa9LHdgRYSwZiNaLMbUyDvlce6HxFPswmZU4u3NGvi9KeHk+pwSgN1BaLTvdNr
  1256  1ymE/FF4QlAR3LdZ3JBK6kECgYEA0wW4/CJ31ZIURoW8SNjh4iMqy0nR8SJVR7q9
  1257  Y/hU2TKDRyEnoIwaohAFayNCrLUh3W5kVAXa8roB+OgDVAECH5sqOfZ+HorofD19
  1258  x8II7ESujLZj1whBXDkm3ovsT7QWZ17lyBZZNvQvBKDPHgKKS8udowv1S4fPGENd
  1259  wS07a4ECgYEAwLSbmMIVJme0jFjsp5d1wOGA2Qi2ZwGIAVlsbnJtygrU/hSBfnu8
  1260  VfyJSCgg3fPe7kChWKlfcOebVKSb68LKRsz1Lz1KdbY0HOJFp/cT4lKmDAlRY9gq
  1261  LB4rdf46lV0mUkvd2/oofIbTrzukjQSnyfLawb/2uJGV1IkTcZcn9CI=
  1262  -----END RSA PRIVATE KEY-----`)