Skip to main content

Custom Schemes

Saucer has support for adding user-defined custom schemes. This mechanism is used by embedding under the hood.

Register Scheme

To add a new custom scheme, you must register the scheme-name before creating any saucer instances.

Example: Register Scheme
#include <saucer/smartview.hpp>

int main()
{
saucer::webview::register_scheme("demo");

auto app = saucer::application::acquire({
.id = "scheme-demo",
});

saucer::smartview smartview{{
.application = app,
}};

smartview.show();
app->run();

return 0;
}

Handle Scheme

After registering a scheme it can be handled per-instance. To do so, call webview.handle_scheme("name", <callback>). The callback will receive a const saucer::scheme::request & and should return either a saucer::scheme::response or an error.

The given request data contains various information on the requested resource, such as the url, request method, body and headers.

Example: Handle Scheme
#include <saucer/smartview.hpp>
#include <print>

int main()
{
saucer::webview::register_scheme("demo");

auto app = saucer::application::acquire({
.id = "scheme-demo",
});

saucer::smartview smartview{{
.application = app,
}};

smartview.handle_scheme("demo",
[](const saucer::scheme::request &req) -> saucer::scheme::handler::result_type
{
std::println("Requested: \"{}\" ({})", req.url(), req.method());

return saucer::scheme::response{
.data = saucer::make_stash("<html><body>Hello from scheme handler!</body></html>"),
.mime = "text/html",
};
});

smartview.set_url("demo://data/index.html");

smartview.show();
app->run();

return 0;
}
caution

Due to upstream issues related to the JS-Fetch API on WebView2, it is required to specify an authority for all scheme-urls.
If none is specified, the given file will be treated as the authority, which may lead to unexpected results.

Example: Add Authority
smartview.set_url("demo://index.html");
smartview.set_url("demo://root/index.html"); // "root" can be any text

It is recommended to always add an authority to your custom-scheme url due to this issue.

As you can see, the response consists of some data and the mime-type. Headers and the status-code can also be optionally specified.

Stash

You might've noticed that saucer::make_stash was used in the example above.
A stash is a storage type for raw-bytes that can be either owning or non-owning.

Example: Owning Data
saucer::stash<>::from(/*data*/);
Example: Viewing Data
saucer::stash<>::view(/*data*/);
tip

You can use saucer::make_stash to conditionally create a (non-)owning stash depending on the given data-type.

caution

Be careful when using stash<>::view. The returned stash will only reference the given data - only use it when you know that the data will outlive the stash.

It is also possible to create a lazy stash, which will compute the data on the first time it is requested and then re-use it later. For more information see embedding.