diff --git a/internal/ingress/metric/collectors/socket.go b/internal/ingress/metric/collectors/socket.go index 0bdd816ae1..1feb785af7 100644 --- a/internal/ingress/metric/collectors/socket.go +++ b/internal/ingress/metric/collectors/socket.go @@ -21,6 +21,7 @@ import ( "io" "net" "os" + "slices" "strings" "syscall" @@ -98,6 +99,19 @@ var requestTags = []string{ "canary", } +var validHTTPMethods = []string{ + // Unless otherwise noted, these are defined in RFC 7231 section 4.3. + "GET", + "HEAD", + "POST", + "PUT", + "PATCH", // RFC 5789 + "DELETE", + "CONNECT", + "OPTIONS", + "TRACE", +} + // NewSocketCollector creates a new SocketCollector instance using // the ingress watch namespace and class used by the controller func NewSocketCollector(pod, namespace, class string, metricsPerHost, metricsPerUndefinedHost, reportStatusClasses bool, buckets HistogramBuckets, bucketFactor float64, maxBuckets uint32, excludeMetrics []string) (*SocketCollector, error) { @@ -316,6 +330,9 @@ func (sc *SocketCollector) handleMessage(msg []byte) { if sc.reportStatusClasses && stats.Status != "" { stats.Status = fmt.Sprintf("%cxx", stats.Status[0]) } + if !slices.Contains(validHTTPMethods, stats.Method) { + stats.Method = "invalid_method" + } // Note these must match the order in requestTags at the top requestLabels := prometheus.Labels{ diff --git a/internal/ingress/metric/collectors/socket_test.go b/internal/ingress/metric/collectors/socket_test.go index 3a1f29f35d..0d3e62ed26 100644 --- a/internal/ingress/metric/collectors/socket_test.go +++ b/internal/ingress/metric/collectors/socket_test.go @@ -648,6 +648,37 @@ func TestCollector(t *testing.T) { metrics: []string{"nginx_ingress_controller_requests"}, useStatusClasses: true, }, + { + name: "invalid http methods should not be set as label values", + data: []string{`[{ + "host":"testshop.com", + "status":"200", + "bytesSent":150.0, + "method":"XYZGET", + "path":"/admin", + "requestLength":300.0, + "requestTime":60.0, + "upstreamLatency":1.0, + "upstreamHeaderTime":5.0, + "upstreamName":"test-upstream", + "upstreamIP":"1.1.1.1:8080", + "upstreamResponseTime":200, + "upstreamStatus":"220", + "namespace":"test-app-production", + "ingress":"web-yml", + "service":"test-app", + "canary":"" + }]`}, + metrics: []string{"nginx_ingress_controller_requests"}, + wantBefore: ` + # HELP nginx_ingress_controller_requests The total number of client requests + # TYPE nginx_ingress_controller_requests counter + nginx_ingress_controller_requests{canary="",controller_class="ingress",controller_namespace="default",controller_pod="pod",host="testshop.com",ingress="web-yml",method="invalid_method",namespace="test-app-production",path="/admin",service="test-app",status="200"} 1 + `, + removeIngresses: []string{"test-app-production/web-yml"}, + wantAfter: ` + `, + }, } for _, c := range cases {