Malloy is a small, embeddable HTTP & WebSocket server & client built on top of boost.beast.
The main use case for this library is a C++ project which needs to embedd an HTTP and/or WebSocket server and/or client.
The following list provides an overview of the currently implemented features. Some of these are optional and can be enabled/disabled.
- High-level controller to setup I/O context, SSL context, worker threads and more
- HTTP
- Plain or TLS (SSL) connections
- Cookies
- Sessions
- Upgrading connections to WebSocket
- Client
- Response filters
- Server
- Routing
- Simple handlers (useful for building REST APIs)
- Target matching via regex
- Capturing groups via regex
- Sub-routers (nested/chained routers)
- Redirections
- File serving locations
- Preflight responses
- Websocket endpoints (with auto-upgrade from HTTP)
- Simple handlers (useful for building REST APIs)
- Request filters
- Routing
- WebSocket
- Client
- Server
- Connections upgradable from HTTP
- HTML
- Forms
- Supported encoding types
application/x-www-form-urlencoded
multipart/form-data
text/plain
- Parsing
- Rendering
- Supported encoding types
- Forms
This library is MIT licensed. Dependencies ship with their own licensing models.
Building (and using) this library requires:
- A C++20 capable compiler
- CMake 3.17 or newer
Required:
- Boost 1.74.0 or newer
- spdlog 1.8.3 or newer
- fmt 7.1.3 or newer (must be compatible with spdlog version)
Optional:
- OpenSSL
A variety of examples can be found in the /examples
directory.
HTTP Server:
int main()
{
const std::filesystem::path doc_root = "../../../../examples/static_content";
// Create malloy controller config
malloy::server::controller::config cfg;
cfg.interface = "127.0.0.1";
cfg.port = 8080;
cfg.doc_root = doc_root;
cfg.num_threads = 5;
// Create malloy controller
malloy::server::controller c;
if (!c.init(cfg)) {
std::cerr << "could not start controller." << std::endl;
return EXIT_FAILURE;
}
// Create the router
auto router = c.router();
if (router) {
using namespace malloy::http;
// A simple GET route handler
router->add(method::get, "/", [](const auto& req) {
response res{status::ok};
res.body() = "<html><body><h1>Hello World!</h1><p>some content...</p></body></html>";
return res;
});
// Add a route to an existing file
router->add(method::get, "/file", [doc_root](const auto& req) {
return generator::file(doc_root, "index.html");
});
// Add some file serving
router->add_file_serving("/files", doc_root);
}
// Start
c.start();
return EXIT_SUCCESS;
}
HTTP client:
int main()
{
// Create the controller config
malloy::client::controller::config cfg;
cfg.num_threads = 1;
cfg.logger = std::make_shared<spdlog::logger>();
// Create the controller
malloy::client::controller c;
if (!c.init(cfg)) {
std::cerr << "initializing controller failed." << std::endl;
return EXIT_FAILURE;
}
// Start
if (!c.start()) {
std::cerr << "starting controller failed." << std::endl;
return EXIT_FAILURE;
}
// Make request
malloy::http::request req(
malloy::http::method::get,
"www.google.com",
80,
"/"
);
auto resp = c.http_request(req);
// Print HTTP response
std::cout << resp.get() << std::endl;
return EXIT_SUCCESS;
}
This started off with the intention of creating a more complex, real-world example of how to use boost.beast
.
This is a work in progress and should generally be perceived as unfit for any production use.
As of today, no security research has been performed on this library.
Malloy is an open-source library provided WITHOUT any WARRANTY or GUARANTEE regarding security, safety, functionality or anything else. Use at your own risk!
Available documentation sources:
- API documentation (doxygen)
The Doxygen API documentation can be generated with little hassle:
doxygen ./Doxyfile
The generated output(s) may be found under /docs/doxygen
. Simply open /docs/doxygen/html/index.html
in the web browser of your choosing.
Malloy is designed to be an embeddable component for other C++ applications.
The easiest way to integrate Malloy is via CMake's FetchContent()
infrastructure:
FetchContent_Declare(
malloy
GIT_REPOSITORY https://github.com/tectu/malloy
GIT_TAG main
)
FetchContent_MakeAvailable(malloy)
If you like to modify set some of Malloy's CMake variables, the FetchContent_MakeAvailable()
call can be replaced accordingly:
FetchContent_Declare(
malloy
GIT_REPOSITORY https://github.com/tectu/malloy
GIT_TAG main
)
FetchContent_GetProperties(malloy)
if(NOT malloy_POPULATED)
FetchContent_Populate(malloy)
set(MALLOY_BUILD_EXAMPLES OFF CACHE INTERNAL "")
set(MALLOY_BUILD_TESTS OFF CACHE INTERNAL "")
set(MALLOY_BUILD_SHARED ON CACHE INTERNAL "")
set(MALLOY_FEATURE_CLIENT OFF CACHE INTERNAL "")
set(MALLOY_FEATURE_SERVER ON CACHE INTERNAL "")
set(MALLOY_FEATURE_TLS ON CACHE INTERNAL "")
add_subdirectory(${malloy_SOURCE_DIR} ${malloy_BINARY_DIR})
endif()
You may replace GIT_TAG
with a commit hash or a release tag such as v1.0.0
.
After fetching the content, it's only a matter of linking the malloy library target to the client application:
target_link_libraries(
my_application
PRIVATE
malloy-objs
)
Where my_application
is your application (or library) target that should consume malloy.
Various cmake
options are available to control the build:
Option | Default | Description |
---|---|---|
MALLOY_BUILD_EXAMPLES |
ON |
Whether to build examples. |
MALLOY_BUILD_TESTS |
ON |
Whether to build the test suite(s). |
MALLOY_BUILD_SHARED |
OFF |
Whether to build shared libraries. If set to OFF , static libraries will be built. |
MALLOY_FEATURE_CLIENT |
ON |
Enable client features. |
MALLOY_FEATURE_SERVER |
ON |
Enable server features. |
MALLOY_FEATURE_HTML |
ON |
Whether to enable HTML support. |
MALLOY_FEATURE_TLS |
OFF |
Whether to enable TLS support. |
MALLOY_DEPENDENCY_SPDLOG_DOWNLOAD |
ON |
Whether to use FetchContent() to pull in spdlog . If set to OFF , find_package() is used instead. |
MALLOY_DEPENDENCY_FMT_DOWNLOAD |
ON |
Same as above but for fmt |