diff --git a/cmd/nodeagent/nodeagentmanager.go b/cmd/nodeagent/nodeagentmanager.go index 882e3fe5..9a272936 100644 --- a/cmd/nodeagent/nodeagentmanager.go +++ b/cmd/nodeagent/nodeagentmanager.go @@ -348,6 +348,10 @@ func (n *NodeAgentManager) heartbeatHandler(w http.ResponseWriter, r *http.Reque ctx := context.Background() re := regexp.MustCompile(`.*/v1/sessionHosts\/(.*?)(/heartbeats|$)`) match := re.FindStringSubmatch(r.RequestURI) + if match == nil { + badRequest(w, fmt.Errorf("invalid request URI"), "cannot parse game server name") + return + } gameServerName := match[1] diff --git a/cmd/nodeagent/nodeagentmanager_test.go b/cmd/nodeagent/nodeagentmanager_test.go index a5b9e3db..85b80a1f 100644 --- a/cmd/nodeagent/nodeagentmanager_test.go +++ b/cmd/nodeagent/nodeagentmanager_test.go @@ -49,6 +49,20 @@ var _ = Describe("nodeagent tests", func() { _, err := io.ReadAll(res.Body) Expect(err).ToNot(HaveOccurred()) }) + It("heartbeat with a request URI that does not match the expected pattern should return error", func() { + req := httptest.NewRequest(http.MethodPost, "/v1/sessionHosts/sessionHostID", nil) + // simulate a request URI that reaches the handler but does not contain the literal path + // (e.g. via a percent-encoded path), so the regex returns no match + req.RequestURI = "/%76%31/sessionHosts/sessionHostID" + w := httptest.NewRecorder() + n := NewNodeAgentManager(newDynamicInterface(), testNodeName, false, false, time.Now, true) + n.heartbeatHandler(w, req) + res := w.Result() + defer res.Body.Close() + Expect(res.StatusCode).To(Equal(http.StatusBadRequest)) + _, err := io.ReadAll(res.Body) + Expect(err).ToNot(HaveOccurred()) + }) It("heartbeat with empty fields should return error", func() { hb := &HeartbeatRequest{} b, _ := json.Marshal(hb) diff --git a/pkg/operator/controllers/allocation_api_server.go b/pkg/operator/controllers/allocation_api_server.go index dada3c3b..ffc8af13 100644 --- a/pkg/operator/controllers/allocation_api_server.go +++ b/pkg/operator/controllers/allocation_api_server.go @@ -209,6 +209,7 @@ func (s *AllocationApiServer) handleAllocationRequest(w http.ResponseWriter, r * if r.Method != http.MethodPost && r.Method != http.MethodPatch { badRequestError(w, s.logger, errors.New("invalid method"), "Only POST and PATCH are accepted") + return } // Parse args diff --git a/pkg/operator/controllers/allocation_api_server_test.go b/pkg/operator/controllers/allocation_api_server_test.go index 11177ed8..32f10208 100644 --- a/pkg/operator/controllers/allocation_api_server_test.go +++ b/pkg/operator/controllers/allocation_api_server_test.go @@ -46,6 +46,29 @@ var _ = Describe("allocation API service input validation tests", func() { _, err := io.ReadAll(res.Body) Expect(err).ToNot(HaveOccurred()) }) + It("GET method with a valid body should return error and not allocate", func() { + client := testNewSimpleK8sClient() + gs, err := testCreateGameServerAndBuild(client, gsName, buildName1, buildID1, "", mpsv1alpha1.GameServerStateStandingBy) + Expect(err).ToNot(HaveOccurred()) + err = testCreatePod(client, gsName) + Expect(err).ToNot(HaveOccurred()) + req := httptest.NewRequest(http.MethodGet, "/api/v1/allocate", bytes.NewBufferString(fmt.Sprintf("{\"sessionID\":\"%s\",\"buildID\":\"%s\"}", sessionID1, buildID1))) + w := httptest.NewRecorder() + h := NewAllocationApiServer(nil, client, allocationApiSvcPort) + h.gameServerQueue = NewGameServersQueue() + h.gameServerQueue.PushToQueue(&GameServerForQueue{ + Name: gsName, + Namespace: "default", + BuildID: buildID1, + ResourceVersion: gs.ObjectMeta.ResourceVersion, + }) + h.handleAllocationRequest(w, req) + res := w.Result() + defer res.Body.Close() + Expect(res.StatusCode).To(Equal(http.StatusBadRequest)) + _, err = io.ReadAll(res.Body) + Expect(err).ToNot(HaveOccurred()) + }) It("bad body should return error", func() { req := httptest.NewRequest(http.MethodPost, "/api/v1/allocate", bytes.NewBufferString("{\"foo\":\"bar\"}")) w := httptest.NewRecorder()