Skip to content

Pin the HTTP command server's behaviour before hardening it - #174

Merged
HugoFara merged 1 commit into
devfrom
test/http-server-characterisation
Aug 12, 2026
Merged

Pin the HTTP command server's behaviour before hardening it#174
HugoFara merged 1 commit into
devfrom
test/http-server-characterisation

Conversation

@HugoFara

Copy link
Copy Markdown
Collaborator

Nothing tested the HTTP server, and it is due for changes to request parsing and path resolution. These seven cases record what it does today, so a regression shows up here rather than as a blank map in someone's browser.

Purely additive: no change to how the server behaves.

What the web console depends on

Both are covered, and any hardening has to preserve them:

The ff: endpoint is the entire UI-to-engine channel. forefireGUI.js sendCommand() posts to / with a body of ff:<command>. It cannot be removed or authenticated away without redesigning the console.

Files resolve against the working directory. buildPlotCommand emits plot[parameter=fuel;filename=fuel.png;...], ForeFire writes fuel.png beside the case, and the browser then fetches /fuel.png as a static file. A document root confined to tools/htdocs would break every map overlay — this is the trap most likely to be hit by a well-intentioned path fix.

Cases

Case Pins
the server binds and accepts a connection basic liveness
a file in the working directory is served the plot-overlay path
a missing file returns 404
a POST body prefixed with ff: reaches the command callback the console channel, and that the prefix is stripped
a GET uri prefixed with /ff: reaches the command callback the alternate form
an ordinary file request does not reach the command callback the static/command split
a request comfortably inside one buffer round-trips intact a size the console can rely on today

Deliberately not covered: path traversal

A test asserting the current behaviour would document an unfixed weakness in a public repository. That case belongs with the fix, when the assertion can be that the request is refused.

Two problems found while writing this, neither fixed here

HttpCommandServer.hpp was not self-contained. It used std::ifstream without including <fstream>, and an unqualified cout, so it compiled only when included after a header that happened to supply both — Command.h was the only such place. Fixed by adding the include and qualifying cout, because the test cannot include the header otherwise. Compile-only; no behaviour change.

stop() deadlocks. It sets running = false, closes the listening socket, then joins the accept thread — but closing a socket does not reliably wake a thread blocked in accept() on Linux, so the join never returns. My first version of this suite hung for exactly this reason.

The suite therefore starts one server and deliberately never stops it; the reasoning is in a comment so nobody "tidies" it later. Nothing has noticed until now because the server is never stopped in normal use — it runs until the process exits. Fixing it needs shutdown() or a self-pipe, which is a change to server behaviour and so is deferred with the rest of the hardening.

Verification

  • Full suite: 29 cases, 2151 assertions, all passing; ctest 4/4.
  • Stable under --order-by=rand across three seeds.
  • runff unchanged — KML and NetCDF both within tolerance.
  • Scratch files are cleaned up; no stray artifacts left in the tree.

Drafted by Claude Opus 5. Reviewed by a maintainer before filing.

Nothing tested the HTTP server, and it is due for changes to request
parsing and path resolution. These seven cases record what it does today,
so a regression shows up here rather than as a blank map in a browser.

Two behaviours the web console depends on and that any hardening must
preserve:

  - POST / with a body of "ff:<command>" reaches the interpreter. That is
    the entire UI-to-engine channel (forefireGUI.js sendCommand).
  - Files resolve against the working directory. The console issues
    plot[filename=fuel.png], ForeFire writes fuel.png beside the case,
    and the browser fetches /fuel.png as a static file. A document root
    that does not cover both htdocs and the working directory would break
    every overlay.

Deliberately not covered: path traversal. Asserting the current
behaviour would document an unfixed weakness in a public repository. Its
test belongs with the fix, when the assertion can be that the request is
refused.

Two problems found while writing this, neither fixed here:

  - HttpCommandServer.hpp was not self-contained. It used std::ifstream
    without including <fstream> and an unqualified cout, so it compiled
    only when included after a header that supplied both. Fixed, because
    the test cannot include it otherwise; no behaviour change.
  - stop() deadlocks. It closes the listening socket and then joins the
    accept thread, but closing a socket does not reliably wake a thread
    blocked in accept() on Linux, so the join never returns. The suite
    therefore starts one server and never stops it. Fixing that needs
    shutdown() or a self-pipe and belongs with the hardening work.
@HugoFara HugoFara self-assigned this Aug 12, 2026
@HugoFara HugoFara added this to the Correctness and code health milestone Aug 12, 2026
@HugoFara
HugoFara merged commit e1df887 into dev Aug 12, 2026
3 checks passed
@antonio-leblanc
antonio-leblanc deleted the test/http-server-characterisation branch August 13, 2026 02:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant