Pure C
asynchronous HTTP framework with support of websockets client/server, TLS 1.2 (SSL), routing.
Works on Linux, macOS, FreeBSD
- Fast asynchronous HTTP server (iwn_http_server.h)
- Web framework based on HTTP server (iwn_wf.h)
- Websocket client and server (iwn_ws_server.h, iwn_ws_client.h)
- Poller reactor (iwn_poller.h)
- SSL Layer is based on BearSSL (iwn_brssl_poller_adapter.h)
- Manager of child processes (iwn_proc.h)
- Timer (iwn_scheduler.h)
Build from sources
Prerequisites
- Linux, macOS or FreeBSD
- CMake 3.12 or greater
- gcc or clang compiler
- GNU Make or Ninja
Building
git clone https://github.com/Softmotions/iwnet.git mkdir -p ./iwnet/build && cd ./iwnet/build cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_EXAMPLES=ON make
Asynchronous HTTP Framework
Examples
Simple echo server
./echo_http_server --ssl curl -k -XPUT -d'Hello' https://localhost:8080/echo Hello I'm an echo web server
echo_http_server.c
#include
#include
#include
#include
static struct iwn_poller *poller;
static struct iwn_wf_ctx *ctx;
static void _on_signal(int signo) {
fprintf(stderr, “nExiting…n”);
iwn_poller_shutdown_request(poller);
}
static int _handle_echo(struct iwn_wf_req *req, void *user_data) {
fprintf(stderr, “Echo handler calledn”);
iwn_http_response_printf(req->http, 200, “text/plain”, “%.*sn%sn”,
(int) req->body_len, req->body, (char*) user_data);
return IWN_WF_RES_PROCESSED;
}
int main(int argc, char *argv[]) {
signal(SIGPIPE, SIG_IGN);
if ( signal(SIGTERM, _on_signal) == SIG_ERR
|| signal(SIGINT, _on_signal) == SIG_ERR) {
return EXIT_FAILURE;
}
iwrc rc = 0;
bool ssl = false;
int port = 8080;
for (int i = 1; i < argc; ++i) {
if (strcmp(argv[i], "--ssl") == 0) {
ssl = true;
} else if (strcmp(argv[i], "--port") == 0 && i + 1 < argc) {
port = iwatoi(argv[i + 1]);
}
}
RCC(rc, finish, iw_init()); // Init iowow runtime, logging, etc..
RCC(rc, finish, iwn_wf_create(0, &ctx)); // Create web server context
RCC(rc, finish, iwn_wf_route(&(struct iwn_wf_route) {
.ctx = ctx,
.pattern = "/echo",
.handler = _handle_echo,
.user_data = "I'm an echo web server",
.flags = IWN_WF_PUT | IWN_WF_POST
}, 0));
RCC(rc, finish, iwn_poller_create(0, 0, &poller));
struct iwn_wf_server_spec spec = {
.listen = "localhost",
.port = port,
.poller = poller,
};
if (ssl) {
spec.ssl.private_key = "./server-eckey.pem";
spec.ssl.private_key_len = -1;
spec.ssl.certs = "./server-ecdsacert.pem";
spec.ssl.certs_len = -1;
}
// Print out a routes configuration.
iwn_wf_route_print(ctx->root, stderr);
// Configure HTTP server.
RCC(rc, finish, iwn_wf_server(&spec, ctx));
fprintf(stderr,
“nOpen terminal and run:ntcurl -k -XPUT -d’Hello’ %s://%s:%dn”,
(ssl ? “https” : “http”),
spec.listen,
spec.port);
// Start fds poller reactor.
iwn_poller_poll(poller);
finish:
iwn_poller_destroy(&poller);
if (rc) {
iwlog_ecode_error3(rc);
return EXIT_FAILURE;
} else {
return EXIT_SUCCESS;
}
}”>
#include "iwn_wf.h" #include <iowow/iwconv.h> #include <stdlib.h> #include <signal.h> #include <string.h> #include <errno.h> static struct iwn_poller *poller; static struct iwn_wf_ctx *ctx; static void _on_signal(int signo) { fprintf(stderr, "nExiting...n"); iwn_poller_shutdown_request(poller); } static int _handle_echo(struct iwn_wf_req *req, void *user_data) { fprintf(stderr, "Echo handler calledn"); iwn_http_response_printf(req->http, 200, "text/plain", "%.*sn%sn", (int) req->body_len, req->body, (char*) user_data); return IWN_WF_RES_PROCESSED; } int main(int argc, char *argv[]) { signal(SIGPIPE, SIG_IGN); if ( signal(SIGTERM, _on_signal) == SIG_ERR || signal(SIGINT, _on_signal) == SIG_ERR) { return EXIT_FAILURE; } iwrc rc = 0; bool ssl = false; int port = 8080; for (int i = 1; i < argc; ++i) { if (strcmp(argv[i], "--ssl") == 0) { ssl = true; } else if (strcmp(argv[i], "--port") == 0 && i + 1 < argc) { port = iwatoi(argv[i + 1]); } } RCC(rc, finish, iw_init()); // Init iowow runtime, logging, etc.. RCC(rc, finish, iwn_wf_create(0, &ctx)); // Create web server context RCC(rc, finish, iwn_wf_route(&(struct iwn_wf_route) { .ctx = ctx, .pattern