Skip to content

Commit 8af33f9

Browse files
authored
Merge pull request kubernetes#81946 from deads2k/cache
add cache-control headers to kube-apiserver
2 parents 8f17e46 + f589c12 commit 8af33f9

File tree

7 files changed

+117
-1
lines changed

7 files changed

+117
-1
lines changed

cmd/controller-manager/app/serve.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@ limitations under the License.
1717
package app
1818

1919
import (
20-
"github.com/prometheus/client_golang/prometheus"
2120
"net/http"
2221
goruntime "runtime"
2322

23+
"github.com/prometheus/client_golang/prometheus"
24+
2425
genericapifilters "k8s.io/apiserver/pkg/endpoints/filters"
2526
apirequest "k8s.io/apiserver/pkg/endpoints/request"
2627
apiserver "k8s.io/apiserver/pkg/server"
@@ -46,6 +47,7 @@ func BuildHandlerChain(apiHandler http.Handler, authorizationInfo *apiserver.Aut
4647
handler = genericapifilters.WithAuthentication(handler, authenticationInfo.Authenticator, failedHandler, nil)
4748
}
4849
handler = genericapifilters.WithRequestInfo(handler, requestInfoResolver)
50+
handler = genericapifilters.WithCacheControl(handler)
4951
handler = genericfilters.WithPanicRecovery(handler)
5052

5153
return handler

cmd/kube-scheduler/app/server.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ func buildHandlerChain(handler http.Handler, authn authenticator.Request, authz
287287
handler = genericapifilters.WithAuthorization(handler, authz, legacyscheme.Codecs)
288288
handler = genericapifilters.WithAuthentication(handler, authn, failedHandler, nil)
289289
handler = genericapifilters.WithRequestInfo(handler, requestInfoResolver)
290+
handler = genericapifilters.WithCacheControl(handler)
290291
handler = genericfilters.WithPanicRecovery(handler)
291292

292293
return handler

pkg/kubeapiserver/server/insecure_handler.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ func BuildInsecureHandlerChain(apiHandler http.Handler, c *server.Config) http.H
3434
handler = genericfilters.WithMaxInFlightLimit(handler, c.MaxRequestsInFlight, c.MaxMutatingRequestsInFlight, c.LongRunningFunc)
3535
handler = genericfilters.WithWaitGroup(handler, c.LongRunningFunc, c.HandlerChainWaitGroup)
3636
handler = genericapifilters.WithRequestInfo(handler, server.NewRequestInfoResolver(c))
37+
handler = genericapifilters.WithCacheControl(handler)
3738
handler = genericfilters.WithPanicRecovery(handler)
3839

3940
return handler

staging/src/k8s.io/apiserver/pkg/endpoints/filters/BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ go_test(
1313
"authentication_test.go",
1414
"authn_audit_test.go",
1515
"authorization_test.go",
16+
"cachecontrol_test.go",
1617
"impersonation_test.go",
1718
"requestinfo_test.go",
1819
],
@@ -44,6 +45,7 @@ go_library(
4445
"authentication.go",
4546
"authn_audit.go",
4647
"authorization.go",
48+
"cachecontrol.go",
4749
"doc.go",
4850
"impersonation.go",
4951
"requestinfo.go",
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
Copyright 2019 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 filters
18+
19+
import (
20+
"net/http"
21+
)
22+
23+
// WithCacheControl sets the Cache-Control header to "no-cache, private" because all servers are protected by authn/authz.
24+
// see https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching#defining_optimal_cache-control_policy
25+
func WithCacheControl(handler http.Handler) http.Handler {
26+
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
27+
// Set the cache-control header if it is not already set
28+
if _, ok := w.Header()["Cache-Control"]; !ok {
29+
w.Header().Set("Cache-Control", "no-cache, private")
30+
}
31+
handler.ServeHTTP(w, req)
32+
})
33+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
Copyright 2019 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 filters
18+
19+
import (
20+
"net/http"
21+
"net/http/httptest"
22+
"testing"
23+
)
24+
25+
func TestCacheControl(t *testing.T) {
26+
tests := []struct {
27+
name string
28+
path string
29+
30+
startingHeader string
31+
expectedHeader string
32+
}{
33+
{
34+
name: "simple",
35+
path: "/api/v1/namespaces",
36+
expectedHeader: "no-cache, private",
37+
},
38+
{
39+
name: "openapi",
40+
path: "/openapi/v2",
41+
expectedHeader: "no-cache, private",
42+
},
43+
{
44+
name: "already-set",
45+
path: "/api/v1/namespaces",
46+
startingHeader: "nonsense",
47+
expectedHeader: "nonsense",
48+
},
49+
}
50+
51+
for _, test := range tests {
52+
t.Run(test.name, func(t *testing.T) {
53+
handler := http.HandlerFunc(func(http.ResponseWriter, *http.Request) {
54+
//do nothing
55+
})
56+
wrapped := WithCacheControl(handler)
57+
58+
testRequest, err := http.NewRequest(http.MethodGet, test.path, nil)
59+
if err != nil {
60+
t.Fatal(err)
61+
}
62+
w := httptest.NewRecorder()
63+
if len(test.startingHeader) > 0 {
64+
w.Header().Set("Cache-Control", test.startingHeader)
65+
}
66+
67+
wrapped.ServeHTTP(w, testRequest)
68+
actual := w.Header().Get("Cache-Control")
69+
70+
if actual != test.expectedHeader {
71+
t.Fatal(actual)
72+
}
73+
})
74+
}
75+
76+
}

staging/src/k8s.io/apiserver/pkg/server/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,7 @@ func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) http.Handler {
599599
handler = genericfilters.WithTimeoutForNonLongRunningRequests(handler, c.LongRunningFunc, c.RequestTimeout)
600600
handler = genericfilters.WithWaitGroup(handler, c.LongRunningFunc, c.HandlerChainWaitGroup)
601601
handler = genericapifilters.WithRequestInfo(handler, c.RequestInfoResolver)
602+
handler = genericapifilters.WithCacheControl(handler)
602603
handler = genericfilters.WithPanicRecovery(handler)
603604
return handler
604605
}

0 commit comments

Comments
 (0)