Open
Conversation
bf49b72 to
03a7536
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
{
"analysis": [
{
"id": 1,
"category": "BUG",
"title": "Query parameter parsing crashes on parameters without a value",
"file": "src/main/java/io/github/dpsoft/ap/functions/Functions.java",
"lines": "22-24",
"issue": "In
splitQueryParams, the code unconditionally callspair.indexOf(\"=\")and then uses the result as an index forsubstring. If a query parameter has no=sign (e.g.,?flagor a malformed query string),indexOfreturns -1, causingpair.substring(0, -1)to throw aStringIndexOutOfBoundsException. This crashes the HTTP handler for any request whose query string contains a bare key or a malformed pair, returning no error to the caller because the exception propagates unhandled out ofhandle().","fix": "Guard against idx == -1 and treat such pairs as boolean flags (value = "") or skip them:\n\n
java\nfor (String pair : pairs) {\n final int idx = pair.indexOf(\"=\");\n if (idx < 0) continue; // skip malformed pair without '='\n final var key = URLDecoder.decode(pair.substring(0, idx), StandardCharsets.UTF_8);\n final var value = URLDecoder.decode(pair.substring(idx + 1), StandardCharsets.UTF_8);\n queryPairs.put(key, value);\n}\n"},
{
"id": 2,
"category": "BUG",
"title": "HTTP 404 response body is never written, leaving the connection in an undefined state",
"file": "src/main/java/io/github/dpsoft/ap/handler/AsyncProfilerHandler.java",
"lines": "28-30",
"issue": "When the requested path is not in the configured context set, the handler calls
sendResponseHeaders(HTTP_NOT_FOUND, 0L)and thenexchange.close(). Passing0Las the content-length tosendResponseHeaderssignals a chunked / streaming response, not an empty body. The JDKHttpServerimplementation requires that either a body is subsequently written to the response body stream or a negative content-length (-1) is passed to indicate zero bytes. Because the body stream is never opened or closed here, the client may never receive a complete HTTP response (the headers frame is sent but the body is never terminated), causing clients to hang. Additionally, anyIOExceptionfromsendResponseHeadersis silently swallowed becauseexchange.close()is called without flushing.","fix": "Pass -1 as the response length (meaning no body) and ensure the exchange is always closed:\n\n
java\nif (!configuration.handler.context().contains(path)) {\n exchange.sendResponseHeaders(HttpURLConnection.HTTP_NOT_FOUND, -1);\n exchange.close();\n return;\n}\n"},
{
"id": 3,
"category": "MISSING_TEST",
"title": "No tests exist anywhere in the project — core parsing logic is completely untested",
"file": "src/main/java/io/github/dpsoft/ap/command/Command.java",
"lines": "46-72",
"issue": "The repository contains zero test sources (there is no
src/testdirectory at all). The most critical pure-logic class,Command, has several non-trivial parsing methods —getOutput,getEventType,getDuration,getEventParams, andasFormatString— that are exercised only at runtime. Edge cases like an unrecognisedoutputvalue falling back toJFR, Go-mode defaulting toPPROF,paramssplitting and--key=value → --key,valuerewriting, and thesecondsalias fordurationare completely untested. The bug inFunctions.splitQueryParams(issue #1) would have been caught immediately by a unit test.","fix": "Add a JUnit 5 test class covering the key branches of
Command.from():\n\njava\n// src/test/java/io/github/dpsoft/ap/command/CommandTest.java\nclass CommandTest {\n\n private static AgentConfiguration config() {\n return AgentConfiguration.instance();\n }\n\n @Test\n void defaultOutputIsJfrWhenParamAbsentAndNotGoMode() {\n var cmd = Command.from(\"profile\", Map.of(), config());\n assertEquals(Command.Output.JFR, cmd.output);\n }\n\n @Test\n void defaultDurationIs30Seconds() {\n var cmd = Command.from(\"profile\", Map.of(), config());\n assertEquals(Duration.ofSeconds(30), cmd.getDuration());\n }\n\n @Test\n void secondsParamIsRespectedAsDurationAlias() {\n var cmd = Command.from(\"profile\", Map.of(\"seconds\", \"60\"), config());\n assertEquals(Duration.ofSeconds(60), cmd.getDuration());\n }\n\n @Test\n void unknownOutputFallsBackToJfr() {\n var cmd = Command.from(\"profile\", Map.of(\"output\", \"unknown\"), config());\n assertEquals(Command.Output.JFR, cmd.output);\n }\n\n @Test\n void eventParamsAreSplitAndPrefixed() {\n var cmd = Command.from(\"profile\", Map.of(\"params\", \"minwidth=1,reverse\"), config());\n assertTrue(cmd.eventParams.contains(\"--minwidth\"));\n assertTrue(cmd.eventParams.contains(\"1\"));\n }\n}\n"}
]
}