feat(cpp-boost-beast-server): add HTTP/1.1 server generator - #24783
Open
bold84 wants to merge 18 commits into
Open
feat(cpp-boost-beast-server): add HTTP/1.1 server generator#24783bold84 wants to merge 18 commits into
bold84 wants to merge 18 commits into
Conversation
…rver Move the direction-agnostic document pipeline, model lowering, parameter serialization facts, dialect policy, and schema-IR emission from CppBoostBeastClientCodegen into CppBoostBeastModelCodegen; extract CppBoostBeastOperationFacts from the client template assembler; add additionalEmbeddedTemplateDirs locator support and move shared model/validation templates to cpp-boost-beast-common. Client generated output is byte-identical; cppboostbeast suite (158 tests) green.
Add the cpp-boost-beast-server generator (BETA) emitting a C++17 Boost.Beast HTTP/1.1 server: strand-per-connection sessions with message_generator responses, encoded-segment routing with 404/405+Allow, OAS parameter deserialization (path simple/label/matrix, query form/space/pipe/deepObject, header simple, cookie form) with enum, pattern, and bound validation into RFC 9457 problem responses, JSON body codec over generated model to/fromJsonValue APIs, OR-of-AND security extraction with a deny-by-default Authorizer seam, single-shot strand posting responders, and an addApiImplStubs quick-start main. CMake links Boost 1.81+ json+url compiled libraries; -Wall/-W4 clean.
…e suites Add the server-regression OAS 3.1 fixture (path/query/header/cookie styles, enum/pattern/bound constraints, bearer + apiKey security), 12-test codegen suite (defaults, contract emission, stubs, IR stripping, multipart/x-www-form-urlencoded/text-*/event-stream/content-style/ cookie-matrix/ambiguous-route rejections, 3.0 compatibility), and the native loopback runtime test compiling and running the generated server against real sockets: 200/201/204 happy paths, 400 problem+json with errors[] for every constraint class, 404, 405+Allow, 413, 415, 401 with and without credentials, keep-alive, label-pattern paths, and pipe-delimited collections. Header params now look up lowercased field names; enum allow-lists render unescaped.
Add the deterministic cpp-boost-beast-server petstore sample (builds clean with -Wall and serves 501 stubs / 400 / 404 over HTTP/1.1), the generated generator documentation, and a three-OS sample build workflow covering Boost json+url consumers. API headers now emit the model namespace using-directive only when an API actually references a generated model class (map-only APIs such as store inventory compile standalone).
…erage Runtime: anonymous security alternatives (security: []) now bypass the authorization gate; 413 body-limit responses close the connection instead of re-reading leftover body bytes as a new request; responses mirror the request HTTP version and keep-alive preference; HttpServer::stop posts the acceptor close onto its strand; ResponderCore's completion flag is atomic and the handler-exception 500 routes through the guard; 401s carry WWW-Authenticate for http-scheme challenges; cookie names strip leading OWS; BodyJson handles uint64 numbers above INT64_MAX without throwing past the invalid_argument catch and supports any-type bodies; parseScalar enforces whole-input match and rejects inf/nan; problem JSON escapes bytes >= 0x7f to keep bodies valid UTF-8. Generator: request-body and parameter $refs are resolved before fact extraction so bodies and constraints survive; declared media-type parameters are normalized out of kMediaTypes; ranged status codes (2XX) and oauth2/openIdConnect/mutualTLS schemes are rejected at generation; integer/number/bool enums are validated at runtime like string enums; header and cookie params gain enum checks; route shape keys mirror the runtime splitter; dead x-server-route/kind/inner facts and the bodyKind helper are removed; shared OperationFacts gains the Apache header. Loopback coverage: anonymous-op bypass against a denying authorizer, integer-enum rejection/acceptance, and conventional spaced Cookie headers.
…tests
Generation gate:
- reject array/object cookie params, non-scalar array items, object
params other than query deepObject string maps, heterogeneous enums
- fix malformed security-scheme diagnostic quoting
Runtime:
- splitMatrixExploded(): strip repeated name= per element for
style=matrix explode=true path parameters
- router literal-over-parameter ranking (most literal segments wins,
ties keep registration order) so /pets/bulk beats /pets/{petId}
- re-arm the stream timer in send_response so deferred handler
completions are not aborted by an expired read deadline
- mirror request version/keep-alive on the 413 body_limit path
- deepObject required-missing now reports 400
- shared param-constraints partial: uniform pattern/length/bound
ladders across query, header, and cookie scalar parameters
- jsonEscape passes UTF-8 through; escapes only C0 controls and DEL
Rendering: minimum/maximum bounds emit long-double-safe literals
(plain integers gain .0), so int64 extremes compile under -Wall.
Tests: four new gate rejection tests plus a deepObject acceptance
test; runtime test hardened (compiler/Boost skip guards, file-based
output redirection, process-tree termination on timeout) and a new
validation-disabled end-to-end case; loopback driver covers matrix
explode, spaceDelimited, deepObject required, literal ranking,
deferred completions, WWW-Authenticate challenges, HTTP/1.0
mirroring incl. 413, cookie decoding, and duplicate-completion
guarding; locator precedence test now probes a template present in
both embedded dirs.
CI: Windows sample job installs boost-asio/beast/multiprecision
ports (the build failed on missing beast and multiprecision headers).
Docs: README ServerOptions table for readTimeoutSeconds/bodyLimitBytes;
sample regenerated deterministically.
bold84
force-pushed
the
pr/cpp-boost-beast-server
branch
from
August 26, 2026 18:45
f8d7a8b to
99775fa
Compare
…rity schemes AllGeneratorsTest requires every registered generator to generate from the canonical 3_0/petstore.yaml, which declares XML/form/multipart payloads and an oauth2 scheme; the previous hard-reject gate broke that contract for the entire project on every CI leg. - preprocessOpenAPI now logs precise warnings for non-JSON request media types, non-JSON response media types, and security scheme types with no runtime credential extractor, while still throwing for the compile-breaking/route-ambiguous categories (parameter styles and shapes, cookie containers, non-scalar array items, non-deepObject object params, heterogeneous enums, ambiguous routes, ranged codes) - the assembler filters declared request media types down to JSON: mixed bodies accept JSON and answer 415 to the rest, JSON-less bodies drop the typed body field entirely (hasBody=false, compiles clean) - unsupported scheme types remain in the route table as declared; the runtime's structurallySatisfied() denies those requests with 401 instead of the generation failing - five rejection tests rewritten as degrade tests asserting the exact generated contracts, plus a canonical-petstore regression test - verified: AllGeneratorsTest 855/855, beast suites 183 green, both samples regenerate with zero diff
The feature set advertised FormUnencoded/FormMultipart support while the server never parses those payloads (they degrade to no typed body). Exclude both parameter features and regenerate the generator docs page.
… variant bodies Move the 16 chunked OAS 3.1 schema-IR templates from the client-only embedded dir into cpp-boost-beast-common so the server generator (whose own dir never carried them) can reach the chunked IR path for large specs, and pin resolution from both generators with a locator test. Wipe the inherited DefaultCodegen typeMapping before seeding it, same as the client generator: AnyType -> oas_any_type_not_mapped is a placeholder header this family never provides, and the OpenAI corpus (FunctionToolParam output_schema anyOf) reaches it through a freeform branch that must resolve to boost::json::value. Render std::variant, std::optional, and std::monostate bodies in BodyJson.h: composition-typed responses serialize the active branch via std::visit, and null branches serialize as JSON null instead of failing to compile.
…d-body JSON members Parameter shapes the JSON runtime cannot decode (content-style, form fields, object/array queries outside deepObject/scalar rules, cookie containers, heterogeneous enums, enum-class dataTypes) now degrade to a dropped handler field with a warning instead of rejecting the document, mirroring the media-type policy so real-world corpora generate code. The OpenAI spec drove the rules: the classifier keys off the resolved dataType the templates emit, so parseScalar can never see a type without an overload. Request-body recovery: a multipart+JSON body whose JSON member $refs a generated model now types the handler body exactly (the model's include is appended via toModelImport when DefaultCodegen did not import it); models aliased to std::variant degrade to no typed body because fromJsonLeaf cannot decode unions; a body model colliding with the generated request struct is namespace-qualified. The model using-directive flag accounts for recovered bodies. The gate now rejects only non-deterministic routing (ambiguous templates, ranged codes). Tests: six degrade rewrites plus four new contracts.
…e the right logger BodyJson.h declares a std::optional overload but relied on <variant> transitively providing <optional>; include it directly. The shared model codegen hardcoded its logger to CppBoostBeastClientCodegen, so server degrade warnings were attributed to the client class; use getClass(). Regenerated petstore server sample picks up the new include.
… rule ArchUnitRulesTest requires slf4j Logger fields to be non-public, non-static and final (PR OpenAPITools#8799); the new assembler logger was static. Both call sites are instance methods, so the field becomes an instance logger.
…tests - Router: tokenize embedded path expressions in one segment; shape keys keep literal text distinct from placeholders - RequestContext held via shared_ptr through the handler/service chain - Optional request bodies no longer fail presence checks when absent - Multi-tag operations get per-operation contract type names - ParamCodecs: float narrowing range checks, exclusive numeric bounds, collection/item constraints (new param-container-constraints include), strict label/matrix percent-encoded codecs, exact integer comparisons - Problem JSON: sanitize malformed UTF-8 in error details - Gate: wildcard response media no longer accepted as JSON; request-body schema selected per declared media; form-encoding hard-reject moved to a server-side override so the shared model path no longer rejects the client corpus; MultiServer feature claim set to false - Generated CMake: warnings are errors by default (opt-out flag added) - README quick-start renders real operations and attach sequence - Runtime regression spec/driver extended to cover all of the above
… regression The sample workflow ran the runtime test with -pl modules/openapi-generator alone, so the 7.26.0-SNAPSHOT sibling (openapi-generator-core) could not be resolved from the snapshot repo on a clean runner checkout. Build the upstream modules with -am and tolerate modules without the selected test.
…l-closed codecs, review gaps - BodyJson: unwrap tagged CompositionBranchValue branches so oneOf responses whose C++ types collide serialize through std::visit - ParamCodecs: reject hex floats explicitly, accept ERANGE underflow, drop the dead errno store; document the whole-input match - param-constraints / param-container-constraints: guard std::regex construction so an out-of-subset pattern fails closed with 400 instead of retry-throwing 500 per request (absent/empty skip it) - Assembler: apiNamespace is constructor-injected (the operations-map merge runs after postProcessOperationsWithModels, which made the collision guard inert); mixed bodies type the JSON member model even when an unparseable member came first; README facts carry model-namespace-qualified send types - Codegen: exclude Host/BasePath global features (never mounted); the server overrides the shared form-encoding reject because it degrades flattened form fields with a warning instead of aborting - Workflow: trigger the sample CI on generator, template, and test resource changes; add generation/runtime coverage for the new paths
Deterministic re-run of bin/generate-samples.sh and bin/utils/export_generator.sh after the fix commit: README quick-start qualifies model response types, BodyJson.h gains the tagged-branch serializer, ParamCodecs.h gains the hex-float gate, and the feature table now reports Host/BasePath as unsupported.
bold84
marked this pull request as ready for review
August 27, 2026 18:37
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.
cpp-boost-beast-server: new OpenAPI HTTP/1.1 server generator (C++17)
Adds a new
cpp-boost-beast-servergenerator that produces a C++17 Boost.Beast HTTP/1.1 server from OpenAPI documents (OAS 3.0 and 3.1). It shares the model pipeline with the client generator (refactored intoCppBoostBeastModelCodegenwithout changing client output) and reuses the OAS 3.1 schema-validation runtime for request-body validation.Scope
Generator
cpp-boost-beast-servergenerator (beta) with typed request/responder contracts per operation (GetPetByIdRequest,GetPetByIdResponder), OAS parameter deserialization (path/query/header/cookie, incl.simple/label/matrix/form/spaceDelimited/pipeDelimited/deepObject-string-map styles), and a security seam (Authorizer, deny-by-default).CppBoostBeastModelCodegen; client output stays byte-identical./a/{x}/cvs/a/{y}/c) and ranged status codes (2XX). Fails closed with precise diagnostics.std::variant(composition unions, including models aliased to one) get no typed body, since decode-side union matching needs the schema matcher the request path does not run.$refs a generated model types the handler body exactly (its#includeis appended viatoModelImport); a body model colliding with the generated request struct is namespace-qualified.application/problem+jsonerrors throughout, withWWW-Authenticatechallenges for http-scheme security.Runtime
HttpServerwith keep-alive, request version/keep-alive mirroring, 413 body-limit handling that closes the connection, and atomic single-completion guard on responders./pets/bulkwins over an earlier-registered/pets/{petId}.security: []or an empty OR-group) bypass the authorization gate with no authorizer required.-Wall.Sample, docs, CI
samples/server/petstore/cpp-boost-beast-server(byte-deterministic regeneration).docs/generators/cpp-boost-beast-server.mdand generator index entry..github/workflows/samples-cpp-boost-beast-server.yaml: Ubuntu / macOS / Windows build matrix with per-OS Boost installs (Windows: vcpkgboost-asio/boost-beast/boost-json/boost-url/boost-multiprecision).Verification
-Wall -Wextraat 0 errors / 0 warnings, and links — exercising the degrade policy (form fields, variant-alias and mixed bodies, enum-class params) and the recovery path (recovered JSON-member bodies with appended includes) at scale.AllGeneratorsTestpasses, i.e. this generator acceptssrc/test/resources/3_0/petstore.yaml(the spec that mixes XML/form/multipart payloads and an oauth2 scheme) exactly as the harness requires — degrade, not reject.-Wallbuild at 0 errors / 0 warnings, and links — exercising the degrade policy (form fields, variant-alias and mixed bodies, enum-class params) and the recovery path (recovered JSON-member bodies with appended includes) at scale.Notes