Harden web-logbook server against malformed pagination query params#585
Merged
Merged
Conversation
The always-on LogHttpServer (started at app launch, LAN-reachable) read the ?page=, ?pageSize= and ?session= query parameters with a raw Integer.parseInt and clamped pageIndex only on the high side. Two defects on untrusted input: - A non-numeric value (?page=abc, a hand-edited URL, a stale bookmark, a truncated link) threw NumberFormatException out of serve(). NanoHTTPD's ClientHandler swallows it (logs, closes the socket), so the browser got an aborted/empty response instead of the requested logbook view. - pageIndex was clamped with `if (pageIndex > pageCount) pageIndex = pageCount` but never floored, so ?page=0 (or a negative page) left pageIndex < 1 and the paged query's `LIMIT (pageIndex - 1) * pageSize, pageSize` offset went negative — a wrong/empty result set numbered from a negative "No." column. Route every query-param parse through a new pure static parseQueryInt(value, fallback) (falls back on null/non-numeric) and every page-index clamp through clampPageIndex(pageIndex, pageCount) (floors to 1; pageCount is always >= 1). Applied at all three paged views (getMessages/getSWLQsoMessages/getQsoLogs) and both import-session handlers. Behaviour is byte-identical for well-formed requests; malformed ones fall back to a sane default instead of breaking. Both helpers are pure and covered by LogHttpServerQueryParamTest (pure JVM, mirrors LogHttpServerPageCountTest); the guard cases fail against the pre-fix behaviour. Verified :app:testDebugUnitTest + :app:assembleDebug (4 ABIs) green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR hardens the always-on LAN-reachable LogHttpServer web-logbook endpoints against malformed pagination/import-session query parameters so that bad ?page=, ?pageSize=, and ?session= values no longer abort responses or produce negative SQL offsets.
Changes:
- Added
parseQueryInt(...)(safe int parsing with fallback) andclampPageIndex(...)(floor/cap for 1-based page indices) toLogHttpServer. - Routed pagination and import-session parsing through these helpers and clamped page indices for the three paged list views.
- Added pure-JVM unit tests covering malformed/whitespace parsing and page-index clamping invariants.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| ft8af/app/src/main/java/com/k1af/ft8af/html/LogHttpServer.java | Introduces safe query-int parsing and page-index clamping, and applies them to paged views and import-session handlers to prevent aborted responses and negative offsets. |
| ft8af/app/src/test/java/com/k1af/ft8af/html/LogHttpServerQueryParamTest.java | Adds JVM unit tests to lock in the new guarded behavior for query parsing and page-index clamping. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
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.
Root cause
The always-on
LogHttpServer(started at app launch inMainViewModel, listening onDEFAULT_PORTfor the whole session — LAN-reachable) parsed its pagination query parameters with rawInteger.parseIntand clamped the page index only on the high side. Two defects on untrusted input:Uncaught
NumberFormatExceptionon non-numeric params.?page=abc/?pageSize=abc/?session=abc(a hand-edited URL, a stale bookmark, a truncated nav link) threw out ofserve(). NanoHTTPD'sClientHandler.run()catchesExceptionbroadly — it logs and closes the socket — so the browser got an aborted/empty response instead of the requested logbook view. (Reliability, not an app crash.)Negative SQL offset from an un-floored page index. Each list handler did
if (pageIndex > pageCount) pageIndex = pageCount;with no< 1floor. So?page=0(or a negative page) leftpageIndex < 1, and the paged query'sLIMIT (pageIndex - 1) * pageSize, pageSizeoffset went negative — a wrong/empty result set numbered from a negative "No." column. (Functional bug affecting existing web-logbook behaviour.)Both stem from the same root: unvalidated pagination query parameters.
Fix
Two pure static helpers, mirroring the file's existing
pageCount/normalizePageSizepattern:parseQueryInt(String value, int fallback)— returnsfallbackwhen the value is null or not a valid integer (also trims whitespace).clampPageIndex(int pageIndex, int pageCount)— floors to1and caps atpageCount(which is always>= 1).Applied at all three paged views (
getMessages,getSWLQsoMessages,getQsoLogs) and both import-session handlers (makeGetImportTaskHTML,doCancelImport, fallback-1= an id matching no task). Behaviour is byte-identical for well-formed requests; malformed ones now fall back to a sane default (page 1 / default page size) instead of breaking the response.Testing
LogHttpServerQueryParamTest(pure JVM, JUnit4 + Truth, no Robolectric — mirrorsLogHttpServerPageCountTest), 8 cases covering valid/null/non-numeric/whitespace parse and the page-index floor/cap plus the "offset never negative" invariant.page=0→ offset-pageSize), pass after../gradlew :app:testDebugUnitTestgreen (full suite)../gradlew :app:assembleDebuggreen (4 ABIs, hamlib/NDK).Risk
Low. Change is confined to
LogHttpServerquery-param parsing; no DSP/decoder/protocol/interop surface touched. Well-formed requests are unchanged.