Boost C++ Libraries

PrevUpHomeNext

Limitations and Roadmap

What boost.taar does not do, by choice or not yet. The same lists, plus the limits inherent to each surface and the recently closed items, live in ROADMAP.md in the repository and are updated as items close.

Inherent to the surfaces, and documented rather than planned: streaming results are REST-only; return types without a JSON representation cannot be RPC or MCP results; REST and MCP sessions are separate stores.

Deliberate, not planned.

  • HTTP/2 and HTTP/3: Beast is HTTP/1.1 only. Terminate h2/h3 in a reverse proxy in front of the server.
  • On-the-fly response compression (gzip, br, zstd): needs a compression dependency. Serve precompressed files (htdocs picks file.br / file.gz by Accept-Encoding) or compress in a proxy.
  • Directory listings (autoindex): an information disclosure risk. Build one as an explicit route if needed.
  • Bandwidth throttling and rate limiting: belong in a proxy, or in an interceptor with a user-supplied limiter.
  • .htaccess, rewrite engines, server-side includes, WebDAV: use matchers, several routes, interceptors and guards instead.
  • Access control as a built-in feature: use interceptors and guards.
  • Custom error pages as a built-in feature: use the soft error handler and the response filter.
Transport and connection handling
  • A client that disconnects from a streamed response is noticed only at the next write; a stream suspended in a long wait keeps waiting. Approach: a concurrent read watcher during streaming that keeps pipelined bytes, or a documented keepalive pattern (MCP streams already send keepalive comments).
  • Generators (chunked_response, async_generator) co_spawn the awaited operation on every co_await inside the body: one frame and spawn per awaited operation. Approach: evaluate Asio experimental::coro or a direct awaiter bridge when it stabilises.
  • Endpoint and session registration (register_request_handler, add_interceptor, tool, method, ...) is not synchronised against serving: configure before run() (documented; no runtime check).
  • context_store has no eviction hook: an MCP session that expires idle is dropped without calling the endpoint's end() (harmless today because a locked entry is never swept, but a hook would make cleanup explicit).
Static files
  • File I/O is blocking and runs on the connection's strand thread; no sendfile. HEAD, 304 and the caches limit it, but a slow disk stalls the serving thread. Approach: Asio stream_file / random_access_file (io_uring on Linux) behind a feature check.
  • Within revalidate_after a file rewritten with the same size is still described by its previous validators (and, when it sits in the memory cache, served with its previous bytes). Approach: file system change notification (inotify, ReadDirectoryChangesW) to invalidate entries.
  • On Windows, : in a segment is refused but reserved device names (CON, NUL, ...), trailing dots and short (8.3) names are not filtered. Approach: reject them in the segment check on Windows.
  • Without path_arg, a route with several placeholders falls back to the whole request path (only the {*} entry or a single argument is picked). Approach: record the greedy placeholder's name in the context when the target matcher captures it.
  • Range requests are always served from the uncompressed file, so a client resuming a compressed download restarts it uncompressed. Approach: apply ranges to the chosen variant once clients that need it appear.
MCP
  • A POST never answers with an SSE stream; server notifications and requests travel only over the GET stream (or stdout on stdio).
  • JSON-RPC request_scope::report_progress does nothing over plain HTTP (no stream to carry it); only MCP and stdio deliver progress.
  • Resource template values are matched raw (no percent decoding); list values are joined with commas.
  • The stdio transport is POSIX-only (posix::stream_descriptor); Windows needs a stream_handle based variant.
Interceptors and guards
  • The response filter cannot see request attributes, so a value minted by an interceptor (such as a request id) cannot be echoed by the filter without being stored elsewhere. Approach: pass the request's matcher::context (or its attributes) to the response filter.
  • guard runs its check on a copy of the request context (one copy of path_args per guarded request); changes to path_args by the check are discarded.
OpenAPI
  • Only boost::described types are hoisted into components.schemas; parameters and responses are not shared as components.
  • Routes protected by interceptors are not documented as secured unless the operation declares security explicitly.
REST
  • A streaming handler under with_session runs its body without the entry's lock; state shared with other requests needs its own synchronisation (documented).
Errors
  • server::tcp still calls the throwing acceptor.local_endpoint(); practically never fails, but it would surface as an Asio exception rather than taar::exception.
Documentation and tooling
  • GCC 16 reports -Wdangling-pointer false positives in test coroutine lambdas; tests are unaffected but the b2 log is noisy.
  • C++26 static reflection (P2996, with annotations from P3394) as the replacement for most of the hand-written introspection, behind a feature check so C++20 and C++23 builds keep the current machinery:
    • callable signature detection (type_traits/callable.hpp, has_call_operator) and the concepts built on it (string_like, container_like, numeric_type, specialization_of), which today also rule out generic lambdas as handlers;
    • context injection and argument binding by parameter type and position;
    • parameter names taken from the callable itself, so rest(&add), rpc.method("add", &add) and mcp.tool("add", ..., &add) need no providers that repeat the names;
    • JSON Schema, JSON conversion and OpenAPI/MCP schemas for plain aggregates and enums without BOOST_DESCRIBE_STRUCT / BOOST_DESCRIBE_ENUM;
    • descriptions, defaults and constraints as annotations on parameters and members, replacing description, with_default and constrained in the common cases.
  • Connection timeouts on the session, modelled on nginx: idle (silent close), header and body (408 Request Timeout, then close) and send (close), with setters on basic_http and defaults of 60, 30, 60 and 60 seconds. Handler time and the gaps of a streaming generator do not count; the body timeout also bounds shielded body reads during shutdown. See Timeouts.
  • The session adds Date (RFC 9110 6.6.1) to every response that does not carry one, cached per second; set_date_header(false) disables it.
  • Reference documentation: the namespaces are documented (Doxygen resolves no reference to a namespace member otherwise), deduction guides are hidden (BoostBook emitted their ids twice), and the remaining references are qualified or rephrased. The docs build reports no unresolved references and no duplicate ids.

Earlier changes are listed in the release notes.


PrevUpHomeNext