Skip to content

Commit 1496983

Browse files
committed
Apply the same style of fix as kubernetes#87913 but for HTTP methods too.
Go does not validate HTTP methods beyond len!=0 and that they don't contain HTTP meta chars like a newline. Also to using string sets instead of maps.
1 parent 07a7c49 commit 1496983

File tree

3 files changed

+40
-8
lines changed

3 files changed

+40
-8
lines changed

pkg/kubelet/server/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ go_library(
3939
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
4040
"//staging/src/k8s.io/apimachinery/pkg/util/proxy:go_default_library",
4141
"//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
42+
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
4243
"//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library",
4344
"//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library",
4445
"//staging/src/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library",

pkg/kubelet/server/server.go

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import (
4747
"k8s.io/apimachinery/pkg/types"
4848
"k8s.io/apimachinery/pkg/util/proxy"
4949
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
50+
"k8s.io/apimachinery/pkg/util/sets"
5051
"k8s.io/apiserver/pkg/authentication/authenticator"
5152
"k8s.io/apiserver/pkg/authorization/authorizer"
5253
"k8s.io/apiserver/pkg/server/healthz"
@@ -89,7 +90,8 @@ type Server struct {
8990
auth AuthInterface
9091
host HostInterface
9192
restfulCont containerInterface
92-
metricsBuckets map[string]bool
93+
metricsBuckets sets.String
94+
metricsMethodBuckets sets.String
9395
resourceAnalyzer stats.ResourceAnalyzer
9496
redirectContainerStreaming bool
9597
}
@@ -226,7 +228,8 @@ func NewServer(
226228
resourceAnalyzer: resourceAnalyzer,
227229
auth: auth,
228230
restfulCont: &filteringContainer{Container: restful.NewContainer()},
229-
metricsBuckets: make(map[string]bool),
231+
metricsBuckets: sets.NewString(),
232+
metricsMethodBuckets: sets.NewString("OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT"),
230233
redirectContainerStreaming: redirectContainerStreaming,
231234
}
232235
if auth != nil {
@@ -285,16 +288,24 @@ func (s *Server) InstallAuthFilter() {
285288
// addMetricsBucketMatcher adds a regexp matcher and the relevant bucket to use when
286289
// it matches. Please be aware this is not thread safe and should not be used dynamically
287290
func (s *Server) addMetricsBucketMatcher(bucket string) {
288-
s.metricsBuckets[bucket] = true
291+
s.metricsBuckets.Insert(bucket)
289292
}
290293

291294
// getMetricBucket find the appropriate metrics reporting bucket for the given path
292295
func (s *Server) getMetricBucket(path string) string {
293296
root := getURLRootPath(path)
294-
if s.metricsBuckets[root] == true {
297+
if s.metricsBuckets.Has(root) {
295298
return root
296299
}
297-
return "Invalid path"
300+
return "other"
301+
}
302+
303+
// getMetricMethodBucket checks for unknown or invalid HTTP verbs
304+
func (s *Server) getMetricMethodBucket(method string) string {
305+
if s.metricsMethodBuckets.Has(method) {
306+
return method
307+
}
308+
return "other"
298309
}
299310

300311
// InstallDefaultHandlers registers the default set of supported HTTP request
@@ -908,7 +919,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
908919
serverType = "readwrite"
909920
}
910921

911-
method, path := req.Method, s.getMetricBucket(req.URL.Path)
922+
method, path := s.getMetricMethodBucket(req.Method), s.getMetricBucket(req.URL.Path)
912923

913924
longRunning := strconv.FormatBool(isLongRunningRequest(path))
914925

pkg/kubelet/server/server_test.go

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1510,8 +1510,8 @@ func TestMetricBuckets(t *testing.T) {
15101510
"stats summary sub": {url: "/stats/summary", bucket: "stats"},
15111511
"stats containerName with uid": {url: "/stats/namespace/podName/uid/containerName", bucket: "stats"},
15121512
"stats containerName": {url: "/stats/podName/containerName", bucket: "stats"},
1513-
"invalid path": {url: "/junk", bucket: "Invalid path"},
1514-
"invalid path starting with good": {url: "/healthzjunk", bucket: "Invalid path"},
1513+
"invalid path": {url: "/junk", bucket: "other"},
1514+
"invalid path starting with good": {url: "/healthzjunk", bucket: "other"},
15151515
}
15161516
fw := newServerTest()
15171517
defer fw.testHTTPServer.Close()
@@ -1523,6 +1523,26 @@ func TestMetricBuckets(t *testing.T) {
15231523
}
15241524
}
15251525

1526+
func TestMetricMethodBuckets(t *testing.T) {
1527+
tests := map[string]struct {
1528+
method string
1529+
bucket string
1530+
}{
1531+
"normal GET": {method: "GET", bucket: "GET"},
1532+
"normal POST": {method: "POST", bucket: "POST"},
1533+
"invalid method": {method: "WEIRD", bucket: "other"},
1534+
}
1535+
1536+
fw := newServerTest()
1537+
defer fw.testHTTPServer.Close()
1538+
1539+
for _, test := range tests {
1540+
method := test.method
1541+
bucket := test.bucket
1542+
require.Equal(t, fw.serverUnderTest.getMetricMethodBucket(method), bucket)
1543+
}
1544+
}
1545+
15261546
func TestDebuggingDisabledHandlers(t *testing.T) {
15271547
fw := newServerTestWithDebug(false, false, nil)
15281548
defer fw.testHTTPServer.Close()

0 commit comments

Comments
 (0)