Skip to content

Commit

Permalink
Redirect proxy requests for only GET & HEAD methods
Browse files Browse the repository at this point in the history
- Extract the current redirect code into a function
  (proxyRedirectsforRootPath) and redirect for only
  http.MethodGet or http.MethodHead
- Create a unit test that confirms that only GET &
  HEAD methods are redirected
  • Loading branch information
heyste committed Oct 6, 2021
1 parent 0ac956f commit be65bc3
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 11 deletions.
33 changes: 22 additions & 11 deletions staging/src/k8s.io/apimachinery/pkg/util/proxy/upgradeaware.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,26 @@ func NewUpgradeAwareHandler(location *url.URL, transport http.RoundTripper, wrap
}
}

func proxyRedirectsforRootPath(path string, w http.ResponseWriter, req *http.Request) bool {
redirect := false
method := req.Method

// From pkg/genericapiserver/endpoints/handlers/proxy.go#ServeHTTP:
// Redirect requests with an empty path to a location that ends with a '/'
// This is essentially a hack for http://issue.k8s.io/4958.
// Note: Keep this code after tryUpgrade to not break that flow.
if len(path) == 0 && (method == http.MethodGet || method == http.MethodHead) {
var queryPart string
if len(req.URL.RawQuery) > 0 {
queryPart = "?" + req.URL.RawQuery
}
w.Header().Set("Location", req.URL.Path+"/"+queryPart)
w.WriteHeader(http.StatusMovedPermanently)
redirect = true
}
return redirect
}

// ServeHTTP handles the proxy request
func (h *UpgradeAwareHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
if h.tryUpgrade(w, req) {
Expand All @@ -211,17 +231,8 @@ func (h *UpgradeAwareHandler) ServeHTTP(w http.ResponseWriter, req *http.Request
loc.Path += "/"
}

// From pkg/genericapiserver/endpoints/handlers/proxy.go#ServeHTTP:
// Redirect requests with an empty path to a location that ends with a '/'
// This is essentially a hack for http://issue.k8s.io/4958.
// Note: Keep this code after tryUpgrade to not break that flow.
if len(loc.Path) == 0 {
var queryPart string
if len(req.URL.RawQuery) > 0 {
queryPart = "?" + req.URL.RawQuery
}
w.Header().Set("Location", req.URL.Path+"/"+queryPart)
w.WriteHeader(http.StatusMovedPermanently)
proxyRedirect := proxyRedirectsforRootPath(loc.Path, w, req)
if proxyRedirect {
return
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1055,6 +1055,77 @@ func TestErrorPropagation(t *testing.T) {
}
}

func TestProxyRedirectsforRootPath(t *testing.T) {

tests := []struct {
name string
method string
requestPath string
expectedHeader http.Header
expectedStatusCode int
redirect bool
}{
{
name: "root path, simple get",
method: "GET",
requestPath: "",
redirect: true,
expectedStatusCode: 301,
expectedHeader: http.Header{
"Location": []string{"/"},
},
},
{
name: "root path, simple put",
method: "PUT",
requestPath: "",
redirect: false,
expectedStatusCode: 200,
},
{
name: "root path, simple head",
method: "HEAD",
requestPath: "",
redirect: true,
expectedStatusCode: 301,
expectedHeader: http.Header{
"Location": []string{"/"},
},
},
{
name: "root path, simple delete with params",
method: "DELETE",
requestPath: "",
redirect: false,
expectedStatusCode: 200,
},
}

for _, test := range tests {
func() {
w := httptest.NewRecorder()
req, err := http.NewRequest(test.method, test.requestPath, nil)
if err != nil {
t.Fatal(err)
}

redirect := proxyRedirectsforRootPath(test.requestPath, w, req)
if got, want := redirect, test.redirect; got != want {
t.Errorf("Expected redirect state %v; got %v", want, got)
}

res := w.Result()
if got, want := res.StatusCode, test.expectedStatusCode; got != want {
t.Errorf("Expected status code %d; got %d", want, got)
}

if res.StatusCode == 301 && !reflect.DeepEqual(res.Header, test.expectedHeader) {
t.Errorf("Expected location header to be %v, got %v", test.expectedHeader, res.Header)
}
}()
}
}

// exampleCert was generated from crypto/tls/generate_cert.go with the following command:
// go run generate_cert.go --rsa-bits 1024 --host example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
var exampleCert = []byte(`-----BEGIN CERTIFICATE-----
Expand Down

0 comments on commit be65bc3

Please sign in to comment.