wasi is a header-only helper for C++20 programs built as WebAssembly
components on WASI, one of the libraries of
webcpp. Its first part,
webcpp::wasi::http, is an HTTP handler: a program writes one function, its
main, which turns a request’s method and target into a response, and wasi
exports the handler that wasmtime serve, or any host of wasi:http, calls,
reads the request, calls the main and writes the answer back. It covers WASI
0.2 (wasip2) and WASI 0.3 (wasip3).
This page teaches wasi concept by concept, states what it guarantees, and shows what webcpp’s build does to compile Boost for WASI, with Boost.JSON in a command and in a component. Every program it shows was compiled for wasm32-wasip2 and wasm32-wasip3 and run by wasmtime, and every answer it shows is what that program answered. The reference that closes it lists every name the headers declare.
Introduction
A WebAssembly component is a program that says, in WIT, what it imports from
its host and what it exports to it. wasi:http is the WASI interface of HTTP:
a host of it, such as wasmtime serve, calls the handler a component
exports once for each request it receives, and the handler answers it. The
handler’s signature, and every type it reads and writes, are the C functions
and structs that wit-bindgen generates from the WIT, and they differ between
WASI 0.2 and WASI 0.3.
wasi writes that handler once, for both versions. A program gives it one function, its main, which receives the request’s method and target and returns a response: a status, a content type and a body. Everything between the host and that function, reading the request, freeing it, sending the headers and writing every byte of the body, is wasi’s.
A complete example
A component that greets whoever calls it with GET, and refuses every other
method. Its whole source is one file:
#include <webcpp/wasi/http/entrypoint.hpp>
WEBCPP_WASI_HTTP_MAIN_BEGIN(method, target)
if (method != "GET") {
return {.status = 405, .content_type = "text/plain", .body = "only GET\n"};
}
return {
.status = 200,
.content_type = "text/plain",
.body = "hello from " + std::string(target) + "\n",
};
WEBCPP_WASI_HTTP_MAIN_END()
The two macros open and close the main, whose parameters are named in the
first one: method and target, two std::string_view. The main returns a
webcpp::wasi::http::response, written here with designated initializers.
In a b2 project, the component is one line of a Jamfile, which builds it for wasip2 and for wasip3, serves it with wasmtime, sends it requests and compares its answers with a file (Testing):
webcpp.targets wasip2 wasip3 ; webcpp.serve http_hello.cpp : <library>/webcpp/wasi//http ;
The requests it is sent, one per line, <METHOD> <target>:
GET /v1/greeting?name=ana POST /x
and what it answered, each request written as the curl command that sends
it. curl’s -i also prints the two headers wasmtime adds to every response,
date and transfer-encoding, which are left out here:
$ curl -i -X GET 'http://localhost:8080/v1/greeting?name=ana' HTTP/1.1 200 OK content-type: text/plain hello from /v1/greeting?name=ana $ curl -i -X POST http://localhost:8080/x HTTP/1.1 405 Method Not Allowed content-type: text/plain only GET
The same program builds by hand with wasi-sdk’s clang++, once its
bindings are generated: By hand shows the commands.
Requirements
-
A C++20 compiler for WebAssembly: wasi-sdk 34, whose Clang builds wasm32-wasip2 and wasm32-wasip3. The entry point compiles for those two targets alone; the response compiles everywhere, natively too.
-
wit-bindgen’s C generator, 0.62.0 measured, and the
wasi:httpWIT of the target: thewit/depsdirectory of the Rust cratewasip21.0.4 for WASI 0.2.12, or ofwasip30.9.0 for WASI 0.3.0. -
A host of
wasi:http, such as wasmtime, 50.0.1 measured. -
Nothing else. The headers include only the standard library and the bindings wit-bindgen writes, and need no Boost. They throw, try and catch nothing, and use no RTTI: wasi needs neither exceptions nor RTTI, and imposes neither. webcpp builds every program of it with exceptions on wasip2 and wasip3 (Building for WASI with Boost), where an exception that escapes the main traps the instance (Its rules).
Reading this page
<webcpp/wasi.hpp> includes the whole library, which is
<webcpp/wasi/http/entrypoint.hpp>: the handler and the macros of the main.
<webcpp/wasi/http/response.hpp> holds only the response, for code that
needs nothing of the component ABI. Their names are in the namespace
webcpp::wasi::http, and what is not public in webcpp::wasi::http::detail.
Your main shows how a program writes its main, and The response what it returns. What your build provides lists what a build gives the header, through b2 or by hand, and wasip3 what changes on WASI 0.3. How a request flows follows one request through the handler, and Limits says what the handler does not do. Guarantees states what wasi promises, each promise with the test or the review that holds it. Building for WASI with Boost shows what webcpp’s build does to compile Boost for WASI, with Boost.JSON in a command and in a component, and Testing how a component is tested, and how wasi is.
Your main
A program’s main is the body written between the two macros, as the
complete example’s is (A complete example).
WEBCPP_WASI_HTTP_MAIN_BEGIN(method, target) and
WEBCPP_WASI_HTTP_MAIN_END() define the function
webcpp::wasi::http::http_main, which takes the two std::string_view
parameters the first macro names and returns a
webcpp::wasi::http::response; and, before it, the extern "C" handler the
program’s world exports, which calls it. The handler calls the main once for
each request, and sends what it returns.
| Parameter | What it holds |
|---|---|
|
The request’s method as it travels on the wire: |
|
The request target, its path and its query, as it was sent:
|
Its rules
-
Once per program. The pair defines the main and the handler a component exports, so a program writes it once, in one source file. Other translation units of the program may include the header: it holds only inline functions and macros (guarantee 2).
-
The parameters view the request. The handler frees the request once it has written the response, so the response’s content type may view them; the main copies what it keeps beyond the request (guarantee 3).
-
What the response views outlives the main. The content type is a view the handler reads after the main has returned: a string literal, or a view of the method or the target, never of a string of the main’s own, which is gone by then. The body is a
std::string, a copy. -
The main’s body is inside a function of
webcpp::wasi::http. It names the program’s own code with its full namespace, or with a namespace alias declared at the top of the body, so that no name of wasi’s hides it. -
An exception that escapes it is not caught. The handler catches nothing, so on wasip2 and wasip3, where webcpp builds a program with exceptions, an exception that escapes the main traps the instance, and the response is never sent. wasmtime 50.0.1 then prints the trap and its backtrace on its standard error,
thrown Wasm exceptionamong them, and answers the client with its own500 Internal Server Error, the HTML page it answers an internal error with; it serves the requests after it. -
The target is not parsed. A main that needs the path and the query apart parses the target with a URL library, such as Boost.URL’s
parse_origin_form.
Formatting it
clang-format reads the body as a function’s when its configuration names the
two macros as the start and the end of a block. These are the two keys of
wasi’s own .clang-format that do it:
MacroBlockBegin: "^WEBCPP_WASI_HTTP_MAIN_BEGIN$" MacroBlockEnd: "^WEBCPP_WASI_HTTP_MAIN_END$"
The response
webcpp::wasi::http::response, in <webcpp/wasi/http/response.hpp>, is
what a main returns: an aggregate of three members, each with a default, so
that a designated initializer names only what differs from it, as
{.status = 404} does.
| Member | Type | What it holds |
|---|---|---|
|
|
The status, sent as it is when it lies within 100 to 599, the five classes of HTTP. Outside them the handler answers an internal error instead of the main’s response (guarantee 9). |
|
|
The |
|
|
The body, sent whole, however long. |
The handler sends no other header (guarantee 7).
A response the handler cannot send as the main wrote it, with a status
outside 100 to 599 or a content type the host refuses, is not sent at all:
the handler answers an internal error, before it has committed anything, and
wasmtime 50.0.1 sends that as its own 500 Internal Server Error, an HTML page
that names it. Without the check, wasmtime would send some of those statuses
as 200 OK, and the status of wasi:http, 16 bits wide, would read 65736 as
200, so a main’s bug would reach the client as a success; and a content type
the host refused would be left out without a word.
A content_type is a view rather than a string because it is nearly always
a literal: a view of one costs nothing, where a std::string of
"application/json", 16 characters, would allocate on wasm32, where
libc++ keeps at most 10 in the string itself.
response.hpp includes nothing of the component ABI, and compiles natively
too: the rest of a program builds responses, holds them and passes them
around, as messages between actors for example, and is tested natively,
without a WASI toolchain.
What your build provides
The entry point is only a header, but it leans on what a build gives it: the C bindings of the program’s world, which wit-bindgen generates, and which version of WASI it is built for. A build provides it with these:
| What | Why |
|---|---|
|
It chooses the version. The header stops with |
The bindings, generated with |
The header includes |
|
The glue that calls the handler, and the world’s type, which the component linker reads. |
The directory of the bindings on the include path |
For |
|
The program is a reactor: it exports a handler and has no C |
The host has its part too: wasmtime serve runs a component of wasi with
-S cli, since wasi-libc imports parts of wasi:cli, and on wasip3 with
-S cli,p3 -W component-model-async (wasip3).
With b2
In a b2 project that uses webcpp, a program that exports the HTTP handler
and nothing else links /webcpp/wasi//http, and is done. That target adds
wasi’s headers; generates with wit-bindgen the bindings of the standard
world of the program’s target, which exports wasi:http/incoming-handler
on wasip2 and wasi:http/handler on wasip3, renamed webcpp_wasi_http, and
links them; and defines WEBCPP_WASI_HTTP_P2 on the toolset
clang-wasip2, or WEBCPP_WASI_HTTP_P3 on clang-wasip3. A component is
then an exe with that library and <linkflags>-mexec-model=reactor, which
webcpp.serve adds itself, as the complete example’s Jamfile shows:
webcpp.targets wasip2 wasip3 ; webcpp.serve http_hello.cpp : <library>/webcpp/wasi//http ;
A program whose world exports more than the HTTP handler uses
/webcpp/wasi//wasi, the headers alone, generates its own world’s bindings
with webcpp.wit-bindings, renamed webcpp_wasi_http too, and defines the
macro of its target itself.
b2 looks for each tool only when a target needs it, and a build that needs one that is not there stops, naming it and every place it looked:
| Tool | Where b2 looks |
|---|---|
wit-bindgen |
|
The |
|
wasmtime |
|
A user-config.jam may set any of them as -s does, with
modules.poke : WIT_BINDGEN : <path> ;. A native build needs none of them.
By hand
The same component builds with wasi-sdk and wit-bindgen alone, from a
directory that holds main.cpp, the complete example’s source, and the
world the component exports, wit/world.wit, named as the program likes:
package example:hello;
world service {
export wasi:http/incoming-handler@0.2.12;
}
with wit/deps/ linked to the wasi:http 0.2.12 WIT, the wit/deps
directory of the Rust crate wasip2 1.0.4. wit-bindgen generates the
bindings with the world renamed webcpp_wasi_http; then wasi-sdk’s clang
compiles them as C, and its clang++ compiles and links a reactor, with
exceptions on, as webcpp builds every program (Exceptions on wasip2 and wasip3):
"$WIT_BINDGEN" c --world service --rename-world webcpp_wasi_http \
--out-dir gen wit
"$WASI_SDK/bin/clang" --target=wasm32-wasip2 \
-c gen/webcpp_wasi_http.c -o gen/webcpp_wasi_http.o -Igen
"$WASI_SDK/bin/clang++" --target=wasm32-wasip2 -std=c++20 \
-fwasm-exceptions -mllvm -wasm-use-legacy-eh=false \
-mexec-model=reactor -DWEBCPP_WASI_HTTP_P2 -I"$WASI/include" -Igen \
main.cpp gen/webcpp_wasi_http.o gen/webcpp_wasi_http_component_type.o \
-fwasm-exceptions -lunwind -o hello.wasm
WIT_BINDGEN is the wit-bindgen program, WASI_SDK wasi-sdk’s directory
and WASI wasi’s. wasmtime serve -S cli hello.wasm then serves the
component, which answers the requests of the complete example as its
transcript shows.
These are the commands of example/by_hand/build.sh, which the test
by_hand of wasi’s examples runs in their lane http on wasip2, with the
wasi-sdk, wit-bindgen and WIT the build found, before it serves the
component and compares its answers with the complete example’s transcript
(Testing a component). A change to them that breaks the build or the
answers fails that lane.
wasip3
The same main serves WASI 0.3: only the build differs, and with b2 it
differs by the toolset alone, clang-wasip3. By hand:
-
the world exports
wasi:http/handler@0.3.0, with thewasi:http0.3.0 WIT inwit/deps/, thewit/depsdirectory of the Rust cratewasip30.9.0; -
the bindings are generated with
--async 'wasi:http/handler@0.3.0#handle'beside--rename-world; -
everything is compiled for
--target=wasm32-wasip3, the.cof the bindings with-pthread, and the program with-DWEBCPP_WASI_HTTP_P3; -
wasmtime serves it with
-S cli,p3 -W component-model-async.
The world of By hand then exports the handler of 0.3.0:
package example:hello;
world service {
export wasi:http/handler@0.3.0;
}
and these commands build it, with exceptions on, as webcpp builds every program for wasip2 and wasip3, and as the commands of wasip2 do (Exceptions on wasip2 and wasip3):
"$WIT_BINDGEN" c --world service --rename-world webcpp_wasi_http \
--async 'wasi:http/handler@0.3.0#handle' --out-dir gen wit
"$WASI_SDK/bin/clang" --target=wasm32-wasip3 -pthread \
-c gen/webcpp_wasi_http.c -o gen/webcpp_wasi_http.o -Igen
"$WASI_SDK/bin/clang++" --target=wasm32-wasip3 -std=c++20 \
-fwasm-exceptions -mllvm -wasm-use-legacy-eh=false \
-mexec-model=reactor -DWEBCPP_WASI_HTTP_P3 -I"$WASI/include" -Igen \
main.cpp gen/webcpp_wasi_http.o gen/webcpp_wasi_http_component_type.o \
-fwasm-exceptions -lunwind -o hello.wasm
The test by_hand runs them in its lane on wasip3, and wasmtime serves what
they build with the flags above and no other. With exceptions on, an
exception that escapes the main traps the instance: the handler catches
nothing, and wasmtime 50.0.1 answers the client with its own
500 Internal Server Error (Its rules). Built with
-fno-exceptions in place of the exception flags, on the compile and on
the link, the component answers the same; webcpp measured that once, by
hand, on wasip3, and its lanes build both versions with exceptions.
The handler of wasip3 is lifted asynchronously, but it never gives its task
back to the host to wait: it waits for each write inside the task, and always
ends with EXIT (guarantee 5). On wasip3, context slot
0 of the component model belongs to wasi-libc, and a handler that resumed in
its callback would need it: using it trapped.
How a request flows
The host calls the handler the program exports once per request, and the handler does the same on both versions, in this order:
host (wasmtime serve)
calls the exported handler
exports_wasi_http_incoming_handler_handle (wasip2)
exports_wasi_http_handler_handle (wasip3)
reads the method and the target
calls the main
http_main(method, target) -> response
refuses a status or a content type it cannot send
sends the status and the content-type
writes the body, every byte
wasip2: in chunks of at most 4096 bytes
wasip3: until the stream has taken it all
frees the request
-
It reads the method and the target. A method of HTTP arrives as an enumerator and becomes its name; an extension method arrives as a string, which the main sees as it was sent. The target is the request’s path and query,
"/"when it has none. -
It calls the main, with two views of the request.
-
It refuses what it cannot send as written: a status outside 100 to 599, or a content type the host refuses as a field value, answers an internal error, and nothing of the main’s response is sent (guarantee 9).
-
It sends the response’s head: the status, and the
content-typeheader whencontent_typeis not empty, and no other header (guarantee 7). -
It writes the body, every byte (guarantee 4). On wasip2,
blocking-write-and-flushtakes at most 4096 bytes a call, so the handler writes in chunks of that size, then finishes the body. On wasip3, it writes to the body’s stream until the stream has taken every byte, waiting inside the task when a write blocks, then resolves the trailers future with no trailers. -
It frees the request, only once the response is written, so a content type that views the method or the target is valid while it is sent (guarantee 3).
A failure the host reports before the response is sent answers an internal error. Once it is sent, nothing can be taken back: a body not written whole is reported the way each version defines, on wasip2 by dropping the body without finishing it, and on wasip3 by resolving the trailers future with an internal error (guarantee 6).
Complete host messages and streams
Select /webcpp/wasi//host-http and include
<webcpp/wasi/http/host.hpp> for incoming and outgoing HTTP with exposed
fields, bodies and trailers. This profile imports wasi:http/outgoing-handler
on P2 and wasi:http/client on P3, as well as the monotonic clock used for
transfer deadlines. It does not require a guest TCP reactor or guest TLS.
The existing /webcpp/wasi//http profile and main macros remain available.
incoming_request owns the host request. Read method(), target(),
authority() and headers() before consume(error). A body_reader reads
into caller-owned spans, enforces transfer_options::body_limit, and reports
EOF separately from successful completion. After EOF, call finish to
check the completion result and visit the trailers. On P2 the request or
response owner must outlive its body reader. On P3 consuming the body moves
the request or response and retains its completion future in the reader.
commit_response commits status and fields once and returns a
body_writer. Write partial spans with write_some, or a complete span
with write, then call finish with optional trailers. Dropping a writer
before finishing fails the remaining body. It cannot replace an already
committed response. P3 abandonment resolves the mandatory trailers future
with an error before releasing the writer; simply dropping that writer
would trap in the component ABI.
outgoing_exchange::start takes the scheme, authority, method, path and
fields, starts the host operation and returns a request body writer. Finish
that writer before receive waits for response headers. The returned
incoming_response provides its status, fields and body. The host owns
connection reuse, DNS and HTTPS trust. Invalid or forbidden fields return
an error; the adapter does not silently switch transports or discard them.
message_error retains the pinned interface’s host error discriminant.
The operations above suspend inside the current component task. They are not an
Asio completion-token interface. A transfer can use an absolute monotonic
deadline or a cancellation predicate. Cancellation is checked between
chunks and while waiting, at intervals of at most ten milliseconds, except
when the host itself blocks inside an imported operation. The adapter does
not allocate C++ operation state. Canonical ABI strings and lists still use
the generated bindings’ cabi_realloc; caller-owned bodies and fields use
their own allocator.
Nonblocking body and response operations
<webcpp/wasi/http/poll.hpp> exposes read_task, write_task and
response_task. Each poll performs one bounded readiness step and returns
false while the host operation remains pending. The tasks own their body
resources and, on P3, stable storage for pending stream and future results.
A pending read or write borrows its payload span until a subsequent poll
completes; the caller must keep that span unchanged and alive. Destroying
a task cancels pending host access before releasing resources or storage.
read_task::finish polls body completion and incoming trailers after EOF.
write_task::finish polls outgoing trailers after the final content chunk.
response_task::poll waits for response headers without blocking on the
network. P2 future tasks retain their readiness subscriptions for the
entire pending interval. These primitives allocate no C++ operation
state and can be driven by a component event loop. Beast’s explicit WASI
asynchronous adapter builds completion-token operations over them.
Standard CLI streams
<webcpp/wasi/stdio.hpp> exposes stdio_channel over the pinned wasi-sdk
CLI stream bindings on P2 and P3. Each operation returns a partial byte
count and ready, blocked, eof or failed. The object owns the acquired
stream resources; it neither creates sockets nor interprets protocol bytes.
No caller buffer remains borrowed after a partial operation returns.
The direct CLI adapter avoids wasi-sdk 34’s stdio descriptors, which reject
fcntl(F_SETFL) and always request blocking I/O. Wasmtime 50.0.1 can still
block inside a standard-output host write when its OS pipe fills. Guest
cancellation is then observed after the peer resumes draining. The tests
bound that pause and resume draining concurrently; they do not claim that
the guest can interrupt a blocking host import. Diagnostics belong on
stderr, separately from the protocol on stdout.
Limits
The original main-macro handler hands the main only the method and the target. It reads no
request header and no request body, and sends no response header but
content-type. Use the complete host-message API for a request body,
additional fields, trailers or an outgoing host request.
What it allocates
The handler’s own code allocates nothing: it views the request’s strings where they are, and the response’s content type where the main put it. Two things do allocate, each through its language’s default:
-
The request’s strings. The target, and an extension method’s name, are copied into the component’s memory as the host hands them over, through the
cabi_reallocthe bindings define, which calls wasi-libc’srealloc. The handler frees them once it has written the response. -
The response’s body, a
std::string, which allocates throughstd::allocatoronce it outgrows the 10 characters it holds in itself on wasm32.
What the main allocates besides is the program’s own. A program cannot yet give wasi an allocator of its own for either.
Guarantees
What wasi promises whatever its program does within the rules of its main
(Its rules), and what holds each promise: a
test of wasi’s, which fails when the promise breaks, or review, where no
test can make the host misbehave on demand. A guarantee keeps its number, and
the anchor named after it, so a comment of the code or of a test cites it by
that anchor: (doc: #wasi-invariant-4) sends its reader to the fourth.
b2 libs/wasi/doc, which builds this page, fails on a citation that names no
anchor of it. The tests are those of How wasi is tested.
-
The entry point compiles only for WASI, and for one version. It includes the
webcpp_wasi_http.hof the program’s world, and refuses to compile unless exactly one ofWEBCPP_WASI_HTTP_P2andWEBCPP_WASI_HTTP_P3is defined.response.hppcompiles anywhere. Held byneither_target_refusedandboth_targets_refused, which compile only with the guard’s own error, on wasip2 and on wasip3; by the public headers compiled alone, the entry point on wasip2 and wasip3, and the response there and natively; and byresponse, run natively and on both versions. -
The header defines no function of its own that a program links. The exported
extern "C"functions are defined by the expansion ofWEBCPP_WASI_HTTP_MAIN_BEGIN, in the program; the header holds only inline functions and macros, so every translation unit of a program may include it, and the program writes the pair of macros once. Held byhttp_two_units, a component of two translation units that both include the entry point, which links and answers. -
Nothing written back points into freed memory. The handler frees the method and the target, and drops the request, only after the response is written, so a content type that views the method or the target is still valid when it is sent. The response owns its body, a copy of what the main built it from, so no body views the request. Held by
http_content_type_of_target, whose content type views the target, on wasip2 and on wasip3, which fails when the target is freed before the content type is read; and byresponse, which checks that the body is a copy. -
Every byte of the body is written. On wasip2 in chunks of at most 4096 bytes, the most
blocking-write-and-flushtakes; on wasip3 by writing until the stream has taken every byte. Held byhttp_long_body, whose body of three chunks and some bytes more arrives whole, on wasip2 and on wasip3. Historical tests with wasmtime 47 took the whole body in one write on wasip3, a body of 1 MiB too. The regression with wasmtime 50.0.1 verifies complete delivery, not the number of writes. The loop stands for a host that takes less per write; the test fails when a write is cut short and the remaining bytes are not sent. -
On wasip3, the handler never resumes in its callback. It waits inside the task for every write that blocks, and always ends with
EXIT, because context slot 0 belongs to wasi-libc on wasip3: using it trapped. Held byhttp_long_bodyon wasip3, and every component served there, and by review. -
A failure is reported the way the version defines. One found before the response is committed answers an internal error. After it is committed, a body not written whole is dropped without being finished on wasip2, and on wasip3 the trailers future is resolved with an internal error. Held by review: wasmtime offers no way to make a write fail on demand.
-
The response carries a
content-typeheader only whencontent_typeis not empty, and no other header. Held byhttp_no_content_type, whose answers carry no header for an empty content type and exactly one for a set one. -
wasi names nothing of the programs that use it. The only generated names it uses are those of the standard interfaces and those
--rename-world webcpp_wasi_httpmakes. Held by the lint’s rule on the banned word, which refuses the name of the program wasi was first written for in every file, file name and commit, and by review. -
A response that cannot be sent as the main wrote it is refused, not altered. A status outside 100 to 599, and a content type the host refuses as a field value, are not sent: the handler answers an internal error instead, before anything is committed, on both versions. Held by
http_bad_status, whose statuses 0, 99, 600 and 65736 answer wasmtime’s500 Internal Server Error, and 599 is sent as it is; and byhttp_bad_content_type, whose content types with a CR and an LF, and with a NUL, answer the same, and one with a tab is sent as it is; on wasip2 and on wasip3.
Building for WASI with Boost
wasi itself needs no Boost, but a component rarely stops at its handler: it parses JSON, computes, keeps state. webcpp builds every library it holds for wasm32-wasip2 and wasm32-wasip3, Boost included, and this chapter shows what its build does for that, so that a project of its own can do the same. Every listing below is the build’s own configuration, included from the file the build reads, or a program webcpp compiles and runs on both targets on every build.
Boost.JSON, Boost.System, Boost.Decimal and Boost.MSM build and run on both targets in webcpp’s lanes, as the tests and the examples of its libraries use them; Boost.JSON shows the first in a command and in a component.
The toolsets
The WASI toolsets are b2’s clang, registered against wasi-sdk 34 under the
versions wasip2 and wasip3, so that toolset=clang-wasip2 and
toolset=clang-wasip3 name them. A user-config.jam registers them with
these lines, the first two of which name wasi-sdk’s directory and give it to
the build, which builds the component of a script with it
(How wasi is tested); the CI writes them into the user-config of each
of its WASI lanes, with the directory where it installed wasi-sdk:
local wasi-sdk = /path/to/wasi-sdk ;
modules.poke : WASI_SDK : $(wasi-sdk) ;
using clang : wasip2 : $(wasi-sdk)/bin/clang++
: <cflags>--target=wasm32-wasip2 <cxxflags>--target=wasm32-wasip2
<linkflags>--target=wasm32-wasip2
<archiver>$(wasi-sdk)/bin/llvm-ar <ranlib>$(wasi-sdk)/bin/llvm-ranlib ;
using clang : wasip3 : $(wasi-sdk)/bin/clang++
: <cflags>--target=wasm32-wasip3 <cxxflags>--target=wasm32-wasip3
<linkflags>--target=wasm32-wasip3
<archiver>$(wasi-sdk)/bin/llvm-ar <ranlib>$(wasi-sdk)/bin/llvm-ranlib ;
Each gives the target to the compilers and to the linker, and makes
archives with wasi-sdk’s own llvm-ar and llvm-ranlib.
wasm32-wasip2 is no system b2 knows. webcpp’s Jamroot declares a target
system wasi of its own, whose programs end in .wasm:
if ! wasi in [ feature.values <target-os> ]
{
feature.extend target-os : wasi ;
}
type.set-generated-target-suffix EXE : <target-os>wasi : wasm ;
It declares it after the toolsets of the user-config.jam have loaded, so
that none of the Unix link options that b2 gives the systems it knows, such
as --start-group or an rpath, reaches wasi-sdk’s linker, which rejects
them. Every target of the two toolsets is then built for that system, and
linked statically, since WASI has no shared libraries:
<toolset>clang-wasip2:<target-os>wasi <toolset>clang-wasip3:<target-os>wasi <target-os>wasi:<link>static
A program built so runs with wasmtime, which b2 starts for a test or an
example given testing.launcher=wasmtime on its command line, beside
toolset=clang-wasip2 or toolset=clang-wasip3 (Targets).
Exceptions on wasip2 and wasip3
A program may use exceptions on wasip2 and wasip3, as natively: whether it does is its developer’s choice, and webcpp builds every program for both with them on, encoded as WebAssembly’s exception handling:
<toolset>clang-wasip2,<exception-handling>on:<cxxflags>"-fwasm-exceptions -mllvm -wasm-use-legacy-eh=false" <toolset>clang-wasip2,<exception-handling>on:<linkflags>"-fwasm-exceptions -lunwind" <toolset>clang-wasip3,<exception-handling>on:<cxxflags>"-fwasm-exceptions -mllvm -wasm-use-legacy-eh=false" <toolset>clang-wasip3,<exception-handling>on:<linkflags>"-fwasm-exceptions -lunwind"
-fwasm-exceptions encodes a throw and a catch as WebAssembly instructions,
on the compile and on the link, and -lunwind links the runtime that
unwinds the stack. -mllvm -wasm-use-legacy-eh=false chooses which
instructions: the Clang of wasi-sdk 34 emits by default the legacy encoding
of the proposal’s first version, and wasmtime 47 refuses to run a program
that uses it, saying legacy_exceptions feature required. With the flag,
Clang emits the standard encoding, exnref, which wasmtime runs, and serves
in a component, with no flag of its own.
A program that uses exceptions needs a host that runs that encoding, which
WebAssembly 3.0 made standard: wasmtime 47 or later, or wasmtime 37 to 46
given -W exceptions=y; jco, whose jco transpile is given
--bindgen-enable-wasm-exnref; or another engine of WebAssembly 3.0.
wasi’s handler catches nothing: an exception that escapes the main traps the
instance, and wasmtime 50.0.1 answers the client with its own
500 Internal Server Error (Its rules). A main that may throw
catches what it can answer itself.
A user’s build without exceptions, exception-handling=off, compiles with
-fno-exceptions alone, under which Boost.Config defines
BOOST_NO_EXCEPTIONS, and that asks something of the program. Where Boost
would throw, it calls boost::throw_exception, which its headers declare
and leave to the program to define: a program built without exceptions that
calls it, as Boost.System’s result and Boost.JSON do, does not link
without a definition. webcpp’s
tools/throw_exception.cpp
defines both overloads: each prints what was thrown on the standard error,
and aborts, since a throw in such a build is a defect, never a condition.
webcpp’s build links it into every program a user builds with
exception-handling=off, on any target. A program built by hand without
exceptions compiles with -fno-exceptions -DBOOST_NO_EXCEPTIONS, and
compiles and links that file, or a definition of its own.
So a program that may be built without exceptions asks Boost for errors as
values. The command of Boost.JSON parses with an error_code,
which a broken text sets, and reads the value with if_object and
if_contains, which answer a null pointer for what is not there; as_object
and at would report it by throwing, which in such a build ends the
program.
<webcpp/wasi/config.hpp>, which every public header of wasi includes
first, defines WEBCPP_WASI_NO_EXCEPTIONS when the build has no exceptions
or when the program defines WEBCPP_NO_EXCEPTIONS, which turns off the
exceptions of every webcpp library at once, and a program may define it for
wasi alone, to turn wasi’s exceptions off in a build that has them, as
Boost.Asio’s BOOST_ASIO_NO_EXCEPTIONS does. wasi reads
WEBCPP_NO_EXCEPTIONS itself, since it includes nothing of Boost, nor
<webcpp/config.hpp>, which includes Boost.Config. wasi raises no exception
of its own, so the macro changes nothing in it: it exists so that a program
can set it for every webcpp library alike. The tests config,
config_developer_defined and config_all_off check the three ways it is
defined, natively and on both targets, and the lint refuses a throw in a
public header, even in a template nothing instantiates: an exception goes
through boost::throw_exception.
Boost.JSON
Boost.JSON is not only headers: its definitions are compiled once in a
program, from the translation unit that includes <boost/json/src.hpp>.
webcpp builds that translation unit as the static library
/webcpp//boost_json, once for each variant and target, so that the
program’s own features, such as <exception-handling>off, reach it; a
program links it with <library>/webcpp//boost_json, and needs no compiled
Boost library. wasi’s two programs of this chapter do so:
webcpp.example boost_json_command.cpp : <library>/webcpp//boost_json ; webcpp.serve boost_json_http.cpp : <library>/webcpp/wasi//http <library>/webcpp//boost_json ;
A command
A WASI command is a program with a main, which wasmtime runs as it runs a
program of the system. This one parses a JSON text, reads what it holds and
prints it. It includes Boost.JSON, and Boost.System for the error code, and
calls Boost.JSON’s namespace json:
#include <boost/json.hpp>
#include <boost/system/error_code.hpp>
#include <iostream>
#include <string_view>
namespace json = boost::json;
The text is a literal, so the program reads no input and prints the same on every target:
// What a component could be configured with: its name, its routes and its limits.
constexpr std::string_view config = R"({
"name": "greeter",
"routes": ["/v1/greeting", "/v1/health"],
"limits": {"body": 65536, "debug": false}
})";
main parses it with an error code, reads its name and its routes, changes
one of its limits and prints the limits, then parses a broken text:
int main() {
boost::system::error_code error;
json::value parsed = json::parse(config, error);
json::object* object = parsed.if_object();
if (error || object == nullptr) {
std::cout << "not a configuration: " << error.message() << '\n';
return 1;
}
if (const json::value* name = object->if_contains("name")) {
std::cout << "name: " << json::serialize(*name) << '\n';
}
if (const json::value* routes = object->if_contains("routes");
routes != nullptr && routes->is_array()) {
for (const json::value& route : routes->get_array()) {
std::cout << "route: " << json::serialize(route) << '\n';
}
}
if (json::value* limits = object->if_contains("limits");
limits != nullptr && limits->is_object()) {
limits->get_object()["debug"] = true;
std::cout << "limits: " << json::serialize(*limits) << '\n';
}
const json::value broken = json::parse(R"({"name": })", error);
std::cout << "a broken text: " << error.message() << ", read as " << json::serialize(broken)
<< '\n';
}
It prints, on wasip2 and on wasip3:
name: "greeter"
route: "/v1/greeting"
route: "/v1/health"
limits: {"body":65536,"debug":true}
a broken text: syntax error, read as null
A component
A component that answers JSON: the list of a catalog’s items, and one item by its id. It includes wasi’s entry point and Boost.JSON:
#include <webcpp/wasi/http/entrypoint.hpp>
#include <boost/json.hpp>
#include <array>
#include <charconv>
#include <cstdint>
#include <string_view>
#include <utility>
The catalog is the program’s own code, in a namespace of its own, which an anonymous one keeps to this file: its items, an item as a JSON object, the item a target names, and an answer whose body Boost.JSON writes:
namespace {
namespace catalog {
struct item {
std::int64_t id;
std::string_view name;
};
constexpr std::array items{item{.id = 1, .name = "apple"}, item{.id = 2, .name = "pear"}};
boost::json::object json_of(const item& entry) {
return {{"id", entry.id}, {"name", entry.name}};
}
// The item a target /v1/items/<id> names, or nullptr.
const item* find(std::string_view target) {
constexpr std::string_view prefix = "/v1/items/";
if (!target.starts_with(prefix)) {
return nullptr;
}
const std::string_view digits = target.substr(prefix.size());
std::int64_t id = 0;
const auto [end, error] = std::from_chars(digits.data(), digits.data() + digits.size(), id);
if (error != std::errc{} || end != digits.data() + digits.size()) {
return nullptr;
}
for (const item& entry : items) {
if (entry.id == id) {
return &entry;
}
}
return nullptr;
}
webcpp::wasi::http::response answer(unsigned status, const boost::json::value& body) {
return {
.status = status,
.content_type = "application/json",
.body = boost::json::serialize(body) + "\n",
};
}
} // namespace catalog
} // namespace
The main refuses every method but GET, lists the items, or answers the one
the target names, or that there is none:
WEBCPP_WASI_HTTP_MAIN_BEGIN(method, target)
if (method != "GET") {
return catalog::answer(405, boost::json::object{{"error", "only GET"}});
}
if (target == "/v1/items") {
boost::json::array all;
for (const catalog::item& entry : catalog::items) {
all.push_back(catalog::json_of(entry));
}
return catalog::answer(200, boost::json::object{{"items", std::move(all)}});
}
if (const catalog::item* entry = catalog::find(target)) {
return catalog::answer(200, catalog::json_of(*entry));
}
return catalog::answer(404, boost::json::object{{"error", "no such item"}, {"target", target}});
WEBCPP_WASI_HTTP_MAIN_END()
wasmtime serves it these requests:
GET /v1/items GET /v1/items/2 GET /v1/items/9 GET /v1/items/2x DELETE /v1/items/2
and it answers them so, on wasip2 and on wasip3, the headers wasmtime adds left out:
$ curl -i -X GET http://localhost:8080/v1/items
HTTP/1.1 200 OK
content-type: application/json
{"items":[{"id":1,"name":"apple"},{"id":2,"name":"pear"}]}
$ curl -i -X GET http://localhost:8080/v1/items/2
HTTP/1.1 200 OK
content-type: application/json
{"id":2,"name":"pear"}
$ curl -i -X GET http://localhost:8080/v1/items/9
HTTP/1.1 404 Not Found
content-type: application/json
{"error":"no such item","target":"/v1/items/9"}
$ curl -i -X GET http://localhost:8080/v1/items/2x
HTTP/1.1 404 Not Found
content-type: application/json
{"error":"no such item","target":"/v1/items/2x"}
$ curl -i -X DELETE http://localhost:8080/v1/items/2
HTTP/1.1 405 Method Not Allowed
content-type: application/json
{"error":"only GET"}
What does not build
Boost.Asio 1.92 does not compile for wasm32-wasip2 or wasm32-wasip3 with
wasi-sdk 34: wasi-libc defines no ESHUTDOWN and no ::pause, and its
signal.h stops with #error. It was measured when webcpp’s first library,
xactor, was ported: its Asio driver is built natively alone, and xactor
records why in its example Jamfile and on
its page.
Testing
A component is a program that only a host runs, so its test runs one: it builds the component, has wasmtime serve it, sends it requests and compares its answers with the ones committed beside it. What the main computes needs no host. The response compiles natively, and a main that calls code of the program’s own, as the catalog of A component does, leaves that code to be tested natively, as any other.
Testing a component
In a b2 project that uses webcpp, a served test is one line of a test or example Jamfile, as the complete example’s is:
webcpp.targets wasip2 wasip3 ; webcpp.serve http_hello.cpp : <library>/webcpp/wasi//http ;
webcpp.serve <source> : <requirements> ; declares the test <stem>,
which builds the source as a component for wasip2 and for wasip3, the
Jamfile’s targets among them. It serves the component with
wasmtime serve, with -S cli on wasip2 and -S cli,p3 -W
component-model-async on wasip3, on a port the system chooses, so that two
lanes at once never share one. It then sends it each line of
<stem>.requests, <METHOD> <target>, and passes when the transcript of the
answers equals <stem>.expected, byte for byte; otherwise it fails with the
difference. It is a test of b2’s, which --dump-tests lists and
--out-xml records, so a failure shows in the test matrix. The explicit
target <stem>-component is the same component, to serve by hand.
The transcript writes each request as the curl command that sends it, which a shell runs as it is written:
-
curl -i -X <METHOD> http://localhost:8080<target>, each word quoted where a shell would read it otherwise, as the target?name=anais; -
curl -I <url>forHEAD, sincecurl -X HEADwaits for a body that never comes; -
--request-target '*'before the bare origin for a target that is not a path, the*ofOPTIONS *.
Then come the status line, HTTP/1.1 <status> <reason>, the response’s
headers in lower case and sorted, an empty line and the body as it came.
The headers wasmtime adds to every response, date and transfer-encoding,
are left out, and the host and the port are written fixed, so that one
transcript holds on every machine and every lane. Two requests are separated
by an empty line. tools/component/serve.py, in the superproject, writes
the transcript and holds its format.
A served test runs in a lane of its own, which webcpp.lane declares with
the targets it runs on, as the complete example’s is:
webcpp.lane http : http_hello by_hand boost_json_http : wasip2 wasip3 ;
The lane is the explicit target http of its Jamfile, and the tests it names
become explicit too: b2 on the test and example directories leaves them
out, and b2 libs/wasi/example//http toolset=clang-wasip2
testing.launcher=wasmtime runs them. The continuous integration runs the
lane once per target it names, as it runs that target’s lane, and its tests
reach the test matrix in a column of its own.
How wasi is tested
wasi’s tests are under test/, each declared in test/Jamfile, and each
guarantee of Guarantees names the tests that hold it:
| Test | What it checks |
|---|---|
|
A lightweight_test program: the response’s defaults, a designated initializer that names one member, and that the body is a copy. Run natively, on wasip2 and on wasip3. |
|
A served component: |
|
A served component whose body is three chunks of 4096 bytes and some more, which must arrive whole, every numbered line of it. |
|
A served component: an empty content type sends no header, with a body and without one, and a set one sends exactly one. |
|
A served component of two translation units that both include the entry point, which links and answers. |
|
A served component whose content type views the target, which must arrive as the target reads, on wasip2 and on wasip3. |
|
A served component that answers the status its target names: 0, 99, 600
and 65736 must answer wasmtime’s |
|
A served component whose content types hold a CR and an LF, and a NUL,
which must answer wasmtime’s |
|
A translation unit that defines neither version’s macro, and one that defines both, each compiled and passing only on the guard’s own error, on wasip2 and on wasip3. |
Beside them, test/Jamfile compiles each of the 8 public headers
alone, as the only include of its translation unit, so that a header that
leans on an include it does not make fails, naming it: the entry point and
<webcpp/wasi.hpp> on wasip2 and wasip3, with the bindings and the macro of
each, and the response natively too. The seven served components run in the
lane http of test/Jamfile. example/Jamfile serves, in a lane http
of its own, the complete example and the component of
A component, and runs the command of
A command, comparing what it prints with the .expected
beside it. Its test by_hand, in the same lane, runs the commands of
By hand and wasip3, example/by_hand/build.sh,
and serves the component they build, which must answer as the complete
example does. webcpp.serve-script declares it, with the script and the
stem of the requests and the transcript it shares with the complete example:
webcpp.serve-script by_hand : by_hand/build.sh : http_hello ;
The script is run as build.sh <p2|p3> <component>, with the tools b2 found
for the lane in its environment: WASI_SDK, the directory of wasi-sdk that
the user-config gives (The toolsets), else .local/wasi-sdk,
WIT_BINDGEN, and WASI_WIT, the WIT of the lane’s version.
Targets
wasi’s programs are built for the targets their Jamfiles declare: every
component, and the command, on wasip2 and wasip3; the response, and its
header alone, natively as well. Two requests run the 24 tests
of wasip2, and two the 24 of wasip3: the served ones in the
lanes http, the others with the test and example directories. From the
root of a webcpp checkout:
b2 libs/wasi/test libs/wasi/example toolset=clang-wasip2 testing.launcher=wasmtime-
Builds and runs, for wasm32-wasip2 and with exceptions, every test that is not served, and the command, which wasmtime runs.
toolset=clang-wasip3does the same for wasm32-wasip3. b2 libs/wasi/test//http libs/wasi/example//http toolset=clang-wasip2 testing.launcher=wasmtime-
Runs the lanes
httpof the tests and of the examples: builds the 10 components for wasm32-wasip2 and has wasmtime serve each.toolset=clang-wasip3does the same for wasm32-wasip3: 10 components. Without a WASI toolset, the request stops, naming the toolsets to give, rather than build nothing. b2 libs/wasi/test libs/wasi/example-
Builds and runs, natively, the 6 tests that need no WASI toolchain, and needs none of the tools below.
The WASI toolsets are those of The toolsets. b2 compares
timestamps, so a result that counts is built from scratch, with b2 -a;
b2 libs/wasi/test//http_methods toolset=clang-wasip2
testing.launcher=wasmtime builds and runs one test alone, while working on
it.
The tools a machine needs
A WASI build needs, besides b2 and Boost 1.92:
| Tool | What for |
|---|---|
wasi-sdk 34 |
The Clang that compiles and links for wasm32-wasip2 and wasm32-wasip3, registered as in The toolsets. |
wit-bindgen 0.62.0 |
Generates the C bindings of each world, when a component is built. |
The |
The |
wasmtime 50.0.1 |
Runs every test and example, and serves each component. |
Where b2 looks for each is in With b2; a WASI build that needs one that is not there stops, naming it and every place it looked.
The test matrix
The continuous integration runs wasi’s tests and examples in lanes, one toolset each: the native compilers, and wasip2 and wasip3. Each lane builds from scratch and records what b2 built and ran:
b2 -a --dump-tests --out-xml=<lane>.xml toolset=<toolset> \
libs/wasi/test libs/wasi/example
The lanes http of the tests and of the examples run together, the same
way, on wasip2 and on wasip3, with the target’s toolset, and record their
run under a name of its own, made of the target, the library and the lane:
wasip2.wasi.http for the served tests and examples on wasip2,
wasip3.wasi.http on wasip3:
b2 -a --dump-tests --out-xml=wasip2.wasi.http.xml \
toolset=clang-wasip2 testing.launcher=wasmtime \
libs/wasi/example//http libs/wasi/test//http
webcpp’s tools/report/report.py merges the files of every lane into a
matrix: a page of the libraries by lanes, and a page of each library’s tests
and examples by lanes, the served ones in the columns of the lanes http,
where each cell says whether that program passed in that lane, or how it
failed, at compile time, at link time or when it ran.
With --out-xml, b2 exits 0 even when a test fails, so the report is the
verdict. The matrix is published with the documentation, at
https://webcpporg.github.io/report/.
Reference
Every name wasi declares, in the namespace webcpp::wasi::http, and its
macros, from the Doc Comments of its headers: each with its declaration,
what it does and what it asks of its caller. It is read with the bindings of
wasip2 and WEBCPP_WASI_HTTP_P2, so the macro WEBCPP_WASI_HTTP_EXPORTS
shows the handler of wasip2; wasip3 says what differs on wasip3.
Macros
| Name | Description |
|---|---|
Defines the |
|
Opens the definition of the program’s main, after the handler the target’s world exports. |
|
Closes the definition of the program’s main that |
|
Defined when wasi is built without exceptions: automatically when the compiler has none (where Boost.Config defines |
webcpp::wasi
Namespaces
| Name |
|---|
Types
| Name | Description |
|---|---|
Owns standard WASI CLI streams. |
|
Bytes copied by a partial stream operation, independent of any wire protocol. |
Enums
| Name | Description |
|---|---|
The observable result of a partial host stream operation. |
webcpp::wasi::http
Types
| Name | Description |
|---|---|
A host body reader, with bounded partial I/O and explicit trailers completion. |
|
A committed body writer. |
|
An incoming host request. |
|
A response received from the host client, including its body resource lifetime. |
|
An operation failure, retaining the pinned wasi:http error-code discriminant. |
|
Owning HTTP fields. |
|
An outgoing exchange. |
|
Owns a nonblocking body read and its pending completion resources. |
|
What the program’s main answers one HTTP request with: a status, a content type and a body. |
|
Polls an outgoing exchange’s response without waiting for network readiness. |
|
Limits shared by a transfer. |
|
Owns a nonblocking body write and stable pending trailer storage. |
Type Aliases
| Name | Description |
|---|---|
Owned request resource of the selected WASI ABI. |
|
P2 response commitment resource. |
Enums
| Name | Description |
|---|---|
Errors of a host message operation, independent of a C++ exception runtime. |
Functions
| Name | Description |
|---|---|
Commits response headers once and returns its body writer. |
|
Answers one HTTP request, given its method and its target: the program’s main. |
|
Reports a pre-commit error. |
webcpp::wasi::http::request_handle
Owned request resource of the selected WASI ABI.
Synopsis
Declared in <webcpp/wasi/http/host.hpp>
using request_handle = wasi_http_types_own_incoming_request_t;
webcpp::wasi::http::response_out
P2 response commitment resource.
Synopsis
Declared in <webcpp/wasi/http/host.hpp>
using response_out = wasi_http_types_own_response_outparam_t;
webcpp::wasi::http::body_reader
A host body reader, with bounded partial I/O and explicit trailers completion.
Member Functions
| Name | Description |
|---|---|
|
Constructors |
|
Fails and releases any unfinished body. |
|
Forbids replacing a potentially unfinished body. |
Whether the content stream has reached its end; finish still checks body failure. |
|
Reads at most the supplied span. |
|
Resolves body completion, then visits trailers. |
Friends
| Name | Description |
|---|---|
Owns a nonblocking body read and its pending completion resources. |
webcpp::wasi::http::body_reader::body_reader
Constructors
Synopses
Declared in <webcpp/wasi/http/message.hpp>
Constructs an empty reader.
constexpr
body_reader() = default;
Transfers body ownership.
body_reader(body_reader&&) = default;
Takes ownership of a P2 incoming body.
explicit
body_reader(wasi_http_types_own_incoming_body_t body);
Parameters
| Name | Description |
|---|---|
body |
Incoming body resource. |
webcpp::wasi::http::body_reader::body_reader
Constructs an empty reader.
webcpp::wasi::http::body_reader::body_reader
Transfers body ownership.
webcpp::wasi::http::body_reader::body_reader
Takes ownership of a P2 incoming body.
Synopsis
Declared in <webcpp/wasi/http/message.hpp>
explicit
body_reader(wasi_http_types_own_incoming_body_t body);
Parameters
| Name | Description |
|---|---|
body |
Incoming body resource. |
webcpp::wasi::http::body_reader::~body_reader
Fails and releases any unfinished body.
webcpp::wasi::http::body_reader::operator=
Forbids replacing a potentially unfinished body.
webcpp::wasi::http::body_reader::eof
Whether the content stream has reached its end; finish still checks body failure.
Return Value
Whether the body content stream has ended.
|
Note
|
The return value should not be discarded. |
webcpp::wasi::http::body_reader::read_some
Reads at most the supplied span.
Synopsis
Declared in <webcpp/wasi/http/message.hpp>
std::size_t
read_some(
std::span<char> output,
transfer_options const& options,
message_error& error);
Return Value
The number of bytes transferred before completion or failure.
Parameters
| Name | Description |
|---|---|
output |
Destination bytes. |
options |
Body limit, cancellation and deadline. |
error |
Receives any failure. |
webcpp::wasi::http::body_reader::finish
Resolves body completion, then visits trailers.
Synopsis
Declared in <webcpp/wasi/http/message.hpp>
template<class Visitor>
message_error
finish(
Visitor&& visitor,
transfer_options const& options);
Description
Call after EOF.
Return Value
An empty error value on success, otherwise the failure.
Template Parameters
| Name | Description |
|---|---|
Visitor |
Callable accepting trailer name and value views. |
Parameters
| Name | Description |
|---|---|
visitor |
Callback for the received trailers. |
options |
Cancellation and deadline while waiting for trailers. |
webcpp::wasi::http::body_writer
A committed body writer.
Description
Destruction without finish fails the body, never commits again.
Member Functions
| Name | Description |
|---|---|
|
Constructors |
|
Fails and releases any unfinished outgoing body. |
|
Forbids replacing a potentially unfinished body. |
Writes a partial span, waiting only for host readiness and honouring transfer cancellation. |
|
Writes all supplied bytes, with bounded host buffering. |
|
Finishes the only committed body. |
Friends
| Name | Description |
|---|---|
Owns a nonblocking body write and stable pending trailer storage. |
webcpp::wasi::http::body_writer::body_writer
Constructors
Synopses
Declared in <webcpp/wasi/http/message.hpp>
Constructs an empty writer.
constexpr
body_writer() = default;
Transfers outgoing body ownership.
body_writer(body_writer&&) = default;
Takes ownership of a P2 outgoing body.
explicit
body_writer(wasi_http_types_own_outgoing_body_t body);
Parameters
| Name | Description |
|---|---|
body |
The outgoing body resource. |
webcpp::wasi::http::body_writer::body_writer
Constructs an empty writer.
webcpp::wasi::http::body_writer::body_writer
Transfers outgoing body ownership.
webcpp::wasi::http::body_writer::body_writer
Takes ownership of a P2 outgoing body.
Synopsis
Declared in <webcpp/wasi/http/message.hpp>
explicit
body_writer(wasi_http_types_own_outgoing_body_t body);
Parameters
| Name | Description |
|---|---|
body |
The outgoing body resource. |
webcpp::wasi::http::body_writer::~body_writer
Fails and releases any unfinished outgoing body.
webcpp::wasi::http::body_writer::operator=
Forbids replacing a potentially unfinished body.
webcpp::wasi::http::body_writer::write_some
Writes a partial span, waiting only for host readiness and honouring transfer cancellation.
Synopsis
Declared in <webcpp/wasi/http/message.hpp>
std::size_t
write_some(
std::string_view bytes,
transfer_options const& options,
message_error& error);
Return Value
The number of bytes transferred before completion or failure.
Parameters
| Name | Description |
|---|---|
bytes |
Source payload bytes. |
options |
Cancellation and deadline. |
error |
Receives any transfer failure. |
webcpp::wasi::http::body_writer::write
Writes all supplied bytes, with bounded host buffering.
Synopsis
Declared in <webcpp/wasi/http/message.hpp>
message_error
write(
std::string_view bytes,
transfer_options const& options = {});
Return Value
An empty error value on success, otherwise the failure.
Parameters
| Name | Description |
|---|---|
bytes |
Source payload. |
options |
Cancellation and deadline. |
webcpp::wasi::http::body_writer::finish
Finishes the only committed body.
Synopsis
Declared in <webcpp/wasi/http/message.hpp>
message_error
finish(message_fields* trailers = nullptr);
Return Value
An empty error value on success, otherwise the failure.
Parameters
| Name | Description |
|---|---|
trailers |
Optional fields whose resource is transferred to the host. |
webcpp::wasi::http::incoming_request
An incoming host request.
Description
Its child body must be destroyed before this owner on P2.
Member Functions
| Name | Description |
|---|---|
|
Constructors |
|
Forbids copying resource ownership. |
|
Releases metadata and any unconsumed request. |
Borrows the method name. |
|
Borrows the original path and query. |
|
Borrows the request authority. |
|
Acquires the exposed header fields. |
|
Consumes the content once, after reading metadata. |
webcpp::wasi::http::incoming_request::incoming_request
Constructors
Synopses
Declared in <webcpp/wasi/http/host.hpp>
Forbids copying resource ownership.
incoming_request(incoming_request const&) = delete;
Takes ownership of the incoming request.
explicit
incoming_request(request_handle request);
Parameters
| Name | Description |
|---|---|
request |
Request supplied by the exported handler. |
webcpp::wasi::http::incoming_request::incoming_request
Forbids copying resource ownership.
Synopsis
Declared in <webcpp/wasi/http/host.hpp>
incoming_request(incoming_request const&) = delete;
webcpp::wasi::http::incoming_request::incoming_request
Takes ownership of the incoming request.
Parameters
| Name | Description |
|---|---|
request |
Request supplied by the exported handler. |
webcpp::wasi::http::incoming_request::operator=
Forbids copying resource ownership.
Synopsis
Declared in <webcpp/wasi/http/host.hpp>
incoming_request&
operator=(incoming_request const&) = delete;
webcpp::wasi::http::incoming_request::~incoming_request
Releases metadata and any unconsumed request.
webcpp::wasi::http::incoming_request::method
Borrows the method name.
Return Value
A view valid while this request owner remains alive.
|
Note
|
The return value should not be discarded. |
webcpp::wasi::http::incoming_request::target
Borrows the original path and query.
Return Value
A view valid while this request owner remains alive.
|
Note
|
The return value should not be discarded. |
webcpp::wasi::http::incoming_request::authority
Borrows the request authority.
Return Value
A view valid while this request owner remains alive.
|
Note
|
The return value should not be discarded. |
webcpp::wasi::http::incoming_request::headers
Acquires the exposed header fields.
Return Value
Owning fields exposing the host headers.
|
Note
|
The return value should not be discarded. |
webcpp::wasi::http::incoming_request::consume
Consumes the content once, after reading metadata.
Description
Consumes the response or request body once.
Return Value
The body reader, or an empty reader on failure.
Parameters
| Name | Description |
|---|---|
error |
Receives an invalid-state error on repeated consumption. |
webcpp::wasi::http::incoming_response
A response received from the host client, including its body resource lifetime.
Member Functions
| Name | Description |
|---|---|
|
Constructors |
Replaces response ownership. |
|
Returns the host response status code. |
|
Acquires the exposed header fields. |
|
Consumes the response or request body once. |
webcpp::wasi::http::incoming_response::incoming_response
Constructors
Synopses
Declared in <webcpp/wasi/http/host.hpp>
Constructs an empty response owner.
constexpr
incoming_response() = default;
Transfers response ownership.
incoming_response(incoming_response&&) = default;
Takes ownership of a P2 response.
explicit
incoming_response(wasi_http_types_own_incoming_response_t value);
Parameters
| Name | Description |
|---|---|
value |
Incoming host response. |
webcpp::wasi::http::incoming_response::incoming_response
Constructs an empty response owner.
webcpp::wasi::http::incoming_response::incoming_response
Transfers response ownership.
webcpp::wasi::http::incoming_response::incoming_response
Takes ownership of a P2 response.
Synopsis
Declared in <webcpp/wasi/http/host.hpp>
explicit
incoming_response(wasi_http_types_own_incoming_response_t value);
Parameters
| Name | Description |
|---|---|
value |
Incoming host response. |
webcpp::wasi::http::incoming_response::operator=
Replaces response ownership.
Synopsis
Declared in <webcpp/wasi/http/host.hpp>
incoming_response&
operator=(incoming_response&&) = default;
Return Value
A reference to this object.
webcpp::wasi::http::incoming_response::status
Returns the host response status code.
webcpp::wasi::http::incoming_response::headers
Acquires the exposed header fields.
Return Value
Owning fields exposing the host headers.
|
Note
|
The return value should not be discarded. |
webcpp::wasi::http::incoming_response::consume
Consumes the response or request body once.
Return Value
The body reader, or an empty reader on failure.
Parameters
| Name | Description |
|---|---|
error |
Receives a resource-state failure. |
webcpp::wasi::http::message_error
An operation failure, retaining the pinned wasi:http error-code discriminant.
Member Functions
| Name | Description |
|---|---|
Whether this value represents failure. |
webcpp::wasi::http::message_error::operator bool
Whether this value represents failure.
Return Value
Whether the object holds a resource or failure, as documented.
webcpp::wasi::http::message_error::code
Portable failure classification.
webcpp::wasi::http::message_error::host_code
Host error-code discriminant when code is host_error.
webcpp::wasi::http::message_fields
Owning HTTP fields.
Description
Duplicate values retain their order.
Member Functions
| Name | Description |
|---|---|
|
Constructors |
Replaces the field resource. |
|
Transfers the resource to the component ABI. |
|
Appends a field without silently dropping forbidden values. |
|
Visits borrowed field strings, valid only during the call. |
webcpp::wasi::http::message_fields::message_fields
Constructors
Synopses
Declared in <webcpp/wasi/http/message.hpp>
Constructs empty mutable fields in the host.
Transfers the field resource.
message_fields(message_fields&&) = default;
Takes ownership of host fields.
explicit
message_fields(wasi_http_types_own_fields_t fields);
Parameters
| Name | Description |
|---|---|
fields |
The host resource to consume. |
webcpp::wasi::http::message_fields::message_fields
Constructs empty mutable fields in the host.
webcpp::wasi::http::message_fields::message_fields
Transfers the field resource.
webcpp::wasi::http::message_fields::message_fields
Takes ownership of host fields.
Synopsis
Declared in <webcpp/wasi/http/message.hpp>
explicit
message_fields(wasi_http_types_own_fields_t fields);
Parameters
| Name | Description |
|---|---|
fields |
The host resource to consume. |
webcpp::wasi::http::message_fields::operator=
Replaces the field resource.
Synopsis
Declared in <webcpp/wasi/http/message.hpp>
message_fields&
operator=(message_fields&&) = default;
Return Value
A reference to this object.
webcpp::wasi::http::message_fields::release
Transfers the resource to the component ABI.
Return Value
The resource handle, whose ownership passes to the caller.
webcpp::wasi::http::message_fields::append
Appends a field without silently dropping forbidden values.
Synopsis
Declared in <webcpp/wasi/http/message.hpp>
message_error
append(
std::string_view name,
std::string_view value);
Return Value
An empty error value on success, otherwise the failure.
Parameters
| Name | Description |
|---|---|
name |
Field name. |
value |
Field value. |
webcpp::wasi::http::message_fields::for_each
Visits borrowed field strings, valid only during the call.
Synopsis
Declared in <webcpp/wasi/http/message.hpp>
template<class Visitor>
void
for_each(Visitor&& visitor) const;
Template Parameters
| Name | Description |
|---|---|
Visitor |
Callable accepting name and value string views. |
Parameters
| Name | Description |
|---|---|
visitor |
Callback invoked for each field. |
webcpp::wasi::http::outgoing_exchange
An outgoing exchange.
Description
Destroying it cancels a pending response; send the body before receive.
Member Functions
| Name | Description |
|---|---|
|
Constructors |
|
Forbids duplicate exchange ownership. |
Starts an outgoing host request without guest DNS, TCP or TLS. |
|
Waits for response headers independently of its body. |
Friends
| Name | Description |
|---|---|
Polls an outgoing exchange’s response without waiting for network readiness. |
webcpp::wasi::http::outgoing_exchange::outgoing_exchange
Constructors
Synopses
Declared in <webcpp/wasi/http/host.hpp>
Constructs an idle exchange.
constexpr
outgoing_exchange() = default;
Forbids duplicate exchange ownership.
outgoing_exchange(outgoing_exchange const&) = delete;
webcpp::wasi::http::outgoing_exchange::outgoing_exchange
Constructs an idle exchange.
webcpp::wasi::http::outgoing_exchange::outgoing_exchange
Forbids duplicate exchange ownership.
Synopsis
Declared in <webcpp/wasi/http/host.hpp>
outgoing_exchange(outgoing_exchange const&) = delete;
webcpp::wasi::http::outgoing_exchange::operator=
Forbids duplicate exchange ownership.
Synopsis
Declared in <webcpp/wasi/http/host.hpp>
outgoing_exchange&
operator=(outgoing_exchange const&) = delete;
webcpp::wasi::http::outgoing_exchange::start
Starts an outgoing host request without guest DNS, TCP or TLS.
Synopsis
Declared in <webcpp/wasi/http/host.hpp>
body_writer
start(
std::string_view scheme,
std::string_view authority,
std::string_view method,
std::string_view target,
message_fields headers,
message_error& error);
Return Value
The committed body writer, or an empty writer on failure.
Parameters
| Name | Description |
|---|---|
scheme |
HTTP or HTTPS. |
authority |
Host and optional port. |
method |
HTTP method name. |
target |
Path and query. |
headers |
Fields transferred to the host. |
error |
Receives any request construction or host failure. |
webcpp::wasi::http::outgoing_exchange::receive
Waits for response headers independently of its body.
Synopsis
Declared in <webcpp/wasi/http/host.hpp>
incoming_response
receive(
transfer_options const& options,
message_error& error);
Return Value
The response owner, or an empty owner on failure.
Parameters
| Name | Description |
|---|---|
options |
Cancellation and deadline. |
error |
Receives any host or cancellation failure. |
webcpp::wasi::http::read_task
Owns a nonblocking body read and its pending completion resources.
Description
A pending read borrows the same destination span until a later poll completes. Destroying this object cancels pending host access before releasing resources.
Member Functions
| Name | Description |
|---|---|
|
Constructors |
|
Cancels pending host operations before releasing their borrowed memory. |
Reports whether body content ended; finish still resolves trailers. |
|
Polls one partial read without blocking for data. |
|
Polls trailers and consumption completion after EOF. |
webcpp::wasi::http::read_task::read_task
Constructors
Synopses
Declared in <webcpp/wasi/http/poll.hpp>
Forbids moving a task with host-borrowed result storage.
Takes ownership of an incoming body.
explicit
read_task(body_reader body);
Parameters
| Name | Description |
|---|---|
body |
Incoming body owner. |
webcpp::wasi::http::read_task::read_task
Takes ownership of an incoming body.
Parameters
| Name | Description |
|---|---|
body |
Incoming body owner. |
webcpp::wasi::http::read_task::~read_task
Cancels pending host operations before releasing their borrowed memory.
webcpp::wasi::http::read_task::eof
Reports whether body content ended; finish still resolves trailers.
webcpp::wasi::http::read_task::read
Polls one partial read without blocking for data.
Synopsis
Declared in <webcpp/wasi/http/poll.hpp>
bool
read(
std::span<char> buffer,
std::size_t& count,
transfer_options const& options,
message_error& error);
Return Value
False while pending, true when bytes, EOF or failure are available.
Parameters
| Name | Description |
|---|---|
buffer |
Stable destination while a read is pending. |
count |
Receives the completed byte count. |
options |
Incoming limit, cancellation and deadline. |
error |
Receives any completed failure. |
webcpp::wasi::http::read_task::finish
Polls trailers and consumption completion after EOF.
Synopsis
Declared in <webcpp/wasi/http/poll.hpp>
template<class Visitor>
bool
finish(
Visitor&& visitor,
transfer_options const& options,
message_error& error);
Return Value
False while pending, true on completion or failure.
Template Parameters
| Name | Description |
|---|---|
Visitor |
Callable accepting trailer name and value views. |
Parameters
| Name | Description |
|---|---|
visitor |
Callback for complete trailer fields. |
options |
Cancellation and deadline. |
error |
Receives any completed failure. |
webcpp::wasi::http::response
What the program’s main answers one HTTP request with: a status, a content type and a body.
Description
The handler sends the status, a content-type header when the content type is not empty, and the body; it sends no other header.
|
Note
|
An aggregate whose every member has a default, so that a designated initializer names only what differs: |
Data Members
| Name | Description |
|---|---|
The status code, 200 unless set. |
|
The value of the |
|
The body, sent whole, however long. |
See Also
"The response", in the guide.
webcpp::wasi::http::response::status
The status code, 200 unless set.
Description
It is sent as it is when it lies within 100 to 599, the five classes of HTTP. Outside them the handler sends no response of the main’s and answers an internal error instead, which wasmtime 50.0.1 sends as its own 500 Internal Server Error.
webcpp::wasi::http::response::content_type
The value of the content-type header, which is sent only when it is not empty.
Description
A value the host refuses as a field value, one that holds a CR, an LF or a NUL for example, is not dropped: the handler answers an internal error instead of the response.
|
Note
|
It is read after the main has returned, so it views what outlives the main: a string literal, such as |
webcpp::wasi::http::response_task
Polls an outgoing exchange’s response without waiting for network readiness.
Member Functions
| Name | Description |
|---|---|
|
Borrows a started exchange until response completion. |
Polls response headers once. |
webcpp::wasi::http::response_task::response_task
Borrows a started exchange until response completion.
Synopsis
Declared in <webcpp/wasi/http/poll.hpp>
explicit
response_task(outgoing_exchange& exchange);
Parameters
| Name | Description |
|---|---|
exchange |
Started outgoing host exchange. |
webcpp::wasi::http::response_task::poll
Polls response headers once.
Synopsis
Declared in <webcpp/wasi/http/poll.hpp>
bool
poll(
incoming_response& response,
transfer_options const& options,
message_error& error);
Return Value
False while pending, true on response or failure.
Parameters
| Name | Description |
|---|---|
response |
Receives ownership of the completed response. |
options |
Cancellation and deadline. |
error |
Receives any completed failure. |
webcpp::wasi::http::transfer_options
Limits shared by a transfer.
Description
Cancellation is checked while waiting and between chunks.
Member Functions
| Name | Description |
|---|---|
Sets an absolute monotonic deadline. |
|
Checks the cancellation source and the absolute deadline. |
Data Members
| Name | Description |
|---|---|
Maximum incoming payload size in bytes. |
|
Absolute host monotonic deadline, or the maximum value for none. |
|
Optional cancellation predicate, called on the component task. |
|
Opaque state supplied to the cancellation predicate. |
webcpp::wasi::http::transfer_options::expires_after
Sets an absolute monotonic deadline.
Parameters
| Name | Description |
|---|---|
nanoseconds |
Duration from the current host monotonic time. |
webcpp::wasi::http::transfer_options::check
Checks the cancellation source and the absolute deadline.
Return Value
An empty error value on success, otherwise the failure.
|
Note
|
The return value should not be discarded. |
webcpp::wasi::http::transfer_options::body_limit
Maximum incoming payload size in bytes.
Synopsis
Declared in <webcpp/wasi/http/message.hpp>
uint64_t body_limit = static_cast<long long>(static_cast<std::uint64_t>(1024) * 1024);
webcpp::wasi::http::transfer_options::deadline
Absolute host monotonic deadline, or the maximum value for none.
Synopsis
Declared in <webcpp/wasi/http/message.hpp>
uint64_t deadline = std::numeric_limits<std::uint64_t>::max();
webcpp::wasi::http::transfer_options::cancelled
Optional cancellation predicate, called on the component task.
webcpp::wasi::http::transfer_options::cancellation_context
Opaque state supplied to the cancellation predicate.
webcpp::wasi::http::write_task
Owns a nonblocking body write and stable pending trailer storage.
Member Functions
| Name | Description |
|---|---|
|
Constructors |
|
Cancels pending writes before releasing borrowed payload storage. |
Polls a bounded partial write without waiting for readiness. |
|
Polls the final trailer write without committing another response. |
webcpp::wasi::http::write_task::write_task
Constructors
Synopses
Declared in <webcpp/wasi/http/poll.hpp>
Forbids moving a task with host-borrowed result storage.
write_task(write_task&&) = delete;
Takes ownership of the only outgoing body.
explicit
write_task(body_writer body);
Parameters
| Name | Description |
|---|---|
body |
Outgoing body owner. |
webcpp::wasi::http::write_task::write_task
Forbids moving a task with host-borrowed result storage.
webcpp::wasi::http::write_task::write_task
Takes ownership of the only outgoing body.
Parameters
| Name | Description |
|---|---|
body |
Outgoing body owner. |
webcpp::wasi::http::write_task::~write_task
Cancels pending writes before releasing borrowed payload storage.
webcpp::wasi::http::write_task::write
Polls a bounded partial write without waiting for readiness.
Synopsis
Declared in <webcpp/wasi/http/poll.hpp>
bool
write(
std::string_view bytes,
std::size_t& count,
transfer_options const& options,
message_error& error);
Return Value
False while pending, true when bytes or failure are available.
Parameters
| Name | Description |
|---|---|
bytes |
Stable source until the pending write completes. |
count |
Receives the completed byte count. |
options |
Cancellation and deadline. |
error |
Receives any completed failure. |
webcpp::wasi::http::write_task::finish
Polls the final trailer write without committing another response.
Synopsis
Declared in <webcpp/wasi/http/poll.hpp>
bool
finish(
message_fields* trailers,
message_error& error);
Return Value
False while pending, true on completion or failure.
Parameters
| Name | Description |
|---|---|
trailers |
Optional fields consumed when finishing begins. |
error |
Receives any completed failure. |
webcpp::wasi::http::message_errc
Errors of a host message operation, independent of a C++ exception runtime.
Members
| Name | Description |
|---|---|
|
No failure. |
|
Invalid HTTP metadata. |
|
A field forbidden by the host. |
|
The incoming body exceeded its configured limit. |
|
The caller cancelled the transfer. |
|
The transfer deadline expired. |
|
A stream closed before the operation completed. |
|
A pinned wasi:http error-code. |
|
The resource has already been consumed or finished. |
webcpp::wasi::http::commit_response
Commits response headers once and returns its body writer.
Synopsis
Declared in <webcpp/wasi/http/host.hpp>
body_writer
commit_response(
response_out out,
uint16_t status,
message_fields headers,
message_error& error);
Return Value
The committed body writer, or an empty writer on failure.
Parameters
| Name | Description |
|---|---|
out |
Active response commitment resource. |
status |
HTTP status code. |
headers |
Header fields transferred to the host. |
error |
Receives any pre-commit failure. |
webcpp::wasi::http::http_main
Answers one HTTP request, given its method and its target: the program’s main.
Synopsis
Declared in <webcpp/wasi/http/entrypoint.hpp>
[[nodiscard]]
response
http_main(
std::string_view method,
std::string_view target);
Description
A program defines it once, by writing its body between WEBCPP_WASI_HTTP_MAIN_BEGIN and WEBCPP_WASI_HTTP_MAIN_END; the handler calls it once for each request and sends what it returns. The body is inside a function of the namespace webcpp::wasi::http, so it names the program’s own code with its full namespace, or with a namespace alias declared at its top.
|
Note
|
Both parameters view the request, which the handler frees once it has written the response: the response’s content type may view them, and the main copies what it keeps beyond the request. |
|
Note
|
The handler catches nothing. On wasip2 and wasip3, where webcpp builds a program with exceptions, an exception that escapes the main traps the instance: wasmtime 50.0.1 prints the trap and answers the client with its own |
Parameters
| Name | Description |
|---|---|
method |
The request’s method as it travels on the wire, such as |
target |
The request target, its path and query, such as |
See Also
"Your main", in the guide.
webcpp::wasi::http::refuse_response
Reports a pre-commit error.
Description
Never call after committing.
Parameters
| Name | Description |
|---|---|
out |
Active response commitment resource. |
webcpp::wasi::stdio_channel
Owns standard WASI CLI streams.
Description
Readiness polling waits are bounded to ten milliseconds.
Member Functions
| Name | Description |
|---|---|
|
Acquires the standard input and output streams. |
|
Releases all owned CLI stream resources. |
Reads a partial byte span. |
|
Writes a partial byte span. |
webcpp::wasi::stdio_channel::stdio_channel
Acquires the standard input and output streams.
webcpp::wasi::stdio_channel::~stdio_channel
Releases all owned CLI stream resources.
webcpp::wasi::stdio_channel::read
Reads a partial byte span.
Return Value
The partial byte count and readiness or failure status.
Parameters
| Name | Description |
|---|---|
buffer |
Destination bytes. |
webcpp::wasi::stdio_channel::write
Writes a partial byte span.
Synopsis
Declared in <webcpp/wasi/stdio.hpp>
[[nodiscard]]
stream_result
write(std::span<char const> buffer) const;
Return Value
The partial byte count and readiness or failure status.
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
buffer |
Source bytes. |
webcpp::wasi::stream_result
Bytes copied by a partial stream operation, independent of any wire protocol.
webcpp::wasi::stream_result::count
Bytes copied during this operation.
webcpp::wasi::stream_result::status
Transfer status, distinct from the byte count.
webcpp::wasi::stream_status
The observable result of a partial host stream operation.
Members
| Name | Description |
|---|---|
|
Bytes transferred successfully. |
|
No progress before the bounded wait ended. |
|
Input ended. |
|
The host reported an I/O failure. |
WEBCPP_WASI_HTTP_EXPORTS
Defines the extern "C" handler the target’s world exports, which hands each request to the library’s handler.
Description
On wasip2 that is the handler of wasi:http/incoming-handler; on wasip3, the handler of wasi:http/handler and its callback. WEBCPP_WASI_HTTP_MAIN_BEGIN expands it, so a program that writes its main between the two macros never names it.
|
Note
|
The functions it defines have the names wit-bindgen generates for each world: |
See Also
"How a request flows", in the guide.
WEBCPP_WASI_HTTP_MAIN_BEGIN
Opens the definition of the program’s main, after the handler the target’s world exports.
Synopsis
Declared in <webcpp/wasi/http/entrypoint.hpp>
#define WEBCPP_WASI_HTTP_MAIN_BEGIN(method, target)
Description
The main’s body follows it, returns a webcpp::wasi::http::response for the request, and ends with WEBCPP_WASI_HTTP_MAIN_END. Together they define webcpp::wasi::http::http_main and, before it, the extern "C" handler of WEBCPP_WASI_HTTP_EXPORTS.
|
Note
|
Write the pair once in a program, in one source file: a program has one main and exports one handler. |
Parameters
| Name | Description |
|---|---|
method |
The name the body gives the request’s method, a |
target |
The name the body gives the request target, its path and query, a |
See Also
"Your main", in the guide.
WEBCPP_WASI_HTTP_MAIN_END
Closes the definition of the program’s main that WEBCPP_WASI_HTTP_MAIN_BEGIN opened.
See Also
"Your main", in the guide.
WEBCPP_WASI_NO_EXCEPTIONS
Defined when wasi is built without exceptions: automatically when the compiler has none (where Boost.Config defines BOOST_NO_EXCEPTIONS), when the developer defines WEBCPP_NO_EXCEPTIONS for every webcpp library, or when the developer defines it alone, to disable wasi’s in a build that has them.
Description
wasi raises no exception of its own, and its handler catches none, so the macro changes nothing in it. It is provided so that a program can set it for every webcpp library alike. An exception wasi raised would go through boost::throw_exception, and an API that throws would be absent while this is defined.
See Also
"Exceptions on wasip2 and wasip3", in the guide.
Appendix A: Changelog
What changed in wasi in each version of webcpp, newest first, one line per change. "Unreleased" is what the next version brings. The release notes of every version are on webcpp’s index page.
Unreleased
webcpp 0.1.0
-
Updated Wasmtime instructions to 50.0.1, preserving historical measurements.
-
Fixed a status outside 100-599 answering 200 OK; it now answers an internal error.
-
Fixed a content type viewing the request’s method or target not being sent.
-
Fixed a content type the host refused being dropped silently; it now answers an internal error.
-
Added the
WEBCPP_WASI_NO_EXCEPTIONSconfiguration macro, defined automatically or by the developer. -
Updated the documentation: wasmtime’s versions, the by-hand build, escaping exceptions and a changelog.
-
Added
WEBCPP_NO_EXCEPTIONS, which disables wasi’s exceptions with every webcpp library’s.