Guard the web-logbook upload handler against a missing file1 part - #623
Merged
Merged
Conversation
The always-on web logbook's /IMPORTLOGDATA handler read the multipart
upload as `files.get("file1").hashCode()`. NanoHTTPD's parseBody() only
adds a "file1" entry when the POST/PUT actually carries that file field,
so a malformed or non-form request — or a bare LAN probe of the logbook
port — left the map without the key and the unconditional deref threw a
NullPointerException.
That throw escaped serve() before its try/catch (the IMPORTLOGDATA branch
runs in the leading dispatch chain, ahead of the try at the bottom of
serve), so NanoHTTPD's worker aborted the request with no useful response.
The sibling handlers in this same file were already hardened against
missing path segments (uriSegment, PR #584) and malformed pagination
params (parseQueryInt/clampPageIndex, PR #585); this closes the matching
gap for the upload part.
Fix: extract a bounds-safe `uploadedFilePath(Map)` helper (null when the
part is absent) mirroring the existing static guards, and reject a null
result with the existing html_illegal_command page — the same fallback a
non-POST method already returns — instead of dereferencing it. Well-formed
uploads are byte-identical.
Adds LogHttpServerUploadPartTest (pure-JVM, no Robolectric, mirroring
LogHttpServerUriSegmentTest / LogHttpServerQueryParamTest).
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 LAN-reachable LogHttpServer /IMPORTLOGDATA upload handler against malformed multipart requests that omit the file1 upload part, preventing an uncaught NullPointerException during request dispatch and returning a consistent “illegal command” response instead.
Changes:
- Added
LogHttpServer.uploadedFilePath(Map<String,String>)to safely fetch thefile1temp-file path (null-safe). - Updated
doImportLogFileto reject missingfile1uploads with the existinghtml_illegal_commandpage instead of dereferencingnull. - Added a pure-JVM unit test covering present/missing/wrong-name/null-map/empty-path cases for the new helper.
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 | Adds a null-safe upload-part helper and uses it to guard /IMPORTLOGDATA against missing file1 parts. |
| ft8af/app/src/test/java/com/k1af/ft8af/html/LogHttpServerUploadPartTest.java | Adds pure-JVM regression tests pinning the new upload-part guard behavior. |
💡 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 web logbook server (
LogHttpServer, started unconditionally at app launch and reachable on the LAN) handles ADIF uploads at/IMPORTLOGDATA.doImportLogFileread the multipart upload as:IHTTPSession.parseBody(files)only inserts a"file1"entry when the POST/PUT actually carries a file field with that name. A malformed or non-form request — or a bare LAN probe of the logbook port — leaves the map without the key, soparamisnullandparam.hashCode()throwsNullPointerException.That
NullPointerExceptionis thrown in the leading dispatch chain ofserve()(line ~221), which runs beforeserve()'s owntry/catch(which starts further down and only catchesIOException | ResponseExceptionanyway). The throw therefore escapesserve()entirely. NanoHTTPD's worker (ClientHandler.run()) catches it in its genericcatch (Exception)and logs "Communication with the client broken", so it is not an app crash — the request is aborted with no useful response.This is the last unguarded external-input deref in a file whose siblings were already hardened:
uriList[2]→uriSegment(...)(PR Guard web-logger uriList[2] reads so a missing month segment can't crash the handler #584)?page=/?pageSize=/?session=params →parseQueryInt(...)/clampPageIndex(...)(PR Harden web-logbook server against malformed pagination query params #585)Fix
uploadedFilePath(Map<String,String> files)that returns thefile1temp-file path, ornullwhen the part is absent (also null-safe on a null map). This mirrors the existinguriSegment/parseQueryIntstatic guards and keeps the decision logic unit-testable per the project's Compose/JNI-free testing rule.nullresult with the existingR.string.html_illegal_commandpage — the same fallback a non-POST method already returns — instead of dereferencing it.Well-formed uploads are byte-for-byte identical: a present
file1flows through unchanged.Testing performed
LogHttpServerUploadPartTest— pure-JVM (no Robolectric), mirroringLogHttpServerUriSegmentTest/LogHttpServerQueryParamTest. Covers present part, missing part, wrong field name, null map, and empty-string path (which must stay "present", since the downstreamLogFileImportopens it and fails with a caughtFileNotFoundException)../gradlew :app:testDebugUnitTest— full suite green../gradlew :app:assembleDebug— green (all 4 ABIs, incl. native/hamlib build).Risk assessment
Very low. Pure Java, one added null-guard on an error path plus a thin extracted helper; no protocol, DSP, threading, or native changes; no behavior change for well-formed requests. LAN-facing reliability (category-2) hardening — completes the
LogHttpServerexternal-input sweep.Affected platforms
Android (the web-logbook server is Android-only).