cpp-httplib is an HTTP/HTTPS library for C++. Just copy a single header file, httplib.h, and you're ready to go.
-
When you need a quick HTTP server or client in C++, you want something that just works. That's exactly why I built cpp-httplib. You can start writing both servers and clients in just a few lines of code.
-
The API uses a lambda-based design that feels natural. It runs anywhere you have a C++11 or later compiler. Windows, macOS, Linux — use whatever environment you already have.
-
HTTPS works too. Just link OpenSSL or mbedTLS, and both server and client gain TLS support. Content-Encoding (gzip, Brotli, etc.), file uploads, and other features you actually need in real-world development are all included. WebSocket is also supported.
-
Under the hood, it uses blocking I/O with a thread pool. It's not built for handling massive numbers of simultaneous connections. But for API servers, embedded HTTP in tools, mock servers for testing, and many other use cases, it delivers solid performance.
-
"Solve today's problem, today." That's the kind of simplicity cpp-httplib aims for.
-
Documentation
-
-
A Tour of cpp-httplib — A step-by-step tutorial covering the basics. Start here if you're new
-
Cookbook — A collection of recipes organized by topic. Jump to whatever you need
cpp-httplib isn't just for servers -- it also comes with a full HTTP client. Let's use httplib::Client to send GET and POST requests.
-
Preparing a Test Server
-
To try out the client, you need a server that accepts requests. Save the following code, then compile and run it the same way you did in the previous chapter. We'll cover the server details in the next chapter.
-
-#include "httplib.h"
-#include <iostream>
-
-int main() {
- httplib::Server svr;
-
- svr.Get("/hi", [](const auto &, auto &res) {
- res.set_content("Hello!", "text/plain");
- });
-
- svr.Get("/search", [](const auto &req, auto &res) {
-auto q = req.get_param_value("q");
- res.set_content("Query: " + q, "text/plain");
- });
-
- svr.Post("/post", [](const auto &req, auto &res) {
- res.set_content(req.body, "text/plain");
- });
-
- svr.Post("/submit", [](const auto &req, auto &res) {
- std::string result;
-for (auto &[key, val] : req.params) {
- result += key + " = " + val + "\n";
- }
- res.set_content(result, "text/plain");
- });
-
- svr.Post("/upload", [](const auto &req, auto &res) {
-auto f = req.form.get_file("file");
-auto content = f.filename + " (" + std::to_string(f.content.size()) + " bytes)";
- res.set_content(content, "text/plain");
- });
-
- svr.Get("/users/:id", [](const auto &req, auto &res) {
-auto id = req.path_params.at("id");
- res.set_content("User ID: " + id, "text/plain");
- });
-
- svr.Get(R"(/files/(\d+))", [](const auto &req, auto &res) {
-auto id = req.matches[1];
- res.set_content("File ID: " + std::string(id), "text/plain");
- });
-
- std::cout << "Listening on port 8080..." << std::endl;
- svr.listen("0.0.0.0", 8080);
-}
-
-
-#include "httplib.h"
-#include <iostream>
-
-int main() {
- httplib::Server svr;
-
- svr.Get("/hi", [](const auto &, auto &res) {
- res.set_content("Hello!", "text/plain");
- });
-
- svr.Get("/search", [](const auto &req, auto &res) {
-auto q = req.get_param_value("q");
- res.set_content("Query: " + q, "text/plain");
- });
-
- svr.Post("/post", [](const auto &req, auto &res) {
- res.set_content(req.body, "text/plain");
- });
-
- svr.Post("/submit", [](const auto &req, auto &res) {
- std::string result;
-for (auto &[key, val] : req.params) {
- result += key + " = " + val + "\n";
- }
- res.set_content(result, "text/plain");
- });
-
- svr.Post("/upload", [](const auto &req, auto &res) {
-auto f = req.form.get_file("file");
-auto content = f.filename + " (" + std::to_string(f.content.size()) + " bytes)";
- res.set_content(content, "text/plain");
- });
-
- svr.Get("/users/:id", [](const auto &req, auto &res) {
-auto id = req.path_params.at("id");
- res.set_content("User ID: " + id, "text/plain");
- });
-
- svr.Get(R"(/files/(\d+))", [](const auto &req, auto &res) {
-auto id = req.matches[1];
- res.set_content("File ID: " + std::string(id), "text/plain");
- });
-
- std::cout << "Listening on port 8080..." << std::endl;
- svr.listen("0.0.0.0", 8080);
-}
-
-
-
GET Request
-
Once the server is running, open a separate terminal and give it a try. Let's start with the simplest GET request.
Pass the server address to the httplib::Client constructor, then call Get() to send a request. You can retrieve the status code and body from the returned res.
-
Here's the equivalent curl command.
-
-curl http://localhost:8080/hi
-# Hello!
-
-
-curl http://localhost:8080/hi
-# Hello!
-
-
-
Checking the Response
-
A response contains header information in addition to the status code and body.
In the previous chapter, you sent requests from a client to a test server. Now let's walk through how that server actually works.
-
Starting the Server
-
Once you've registered your routes, call svr.listen() to start the server.
-
-svr.listen("0.0.0.0", 8080);
-
-
-svr.listen("0.0.0.0", 8080);
-
-
-
The first argument is the host, and the second is the port. "0.0.0.0" listens on all network interfaces. Use "127.0.0.1" if you want to accept connections from your own machine only.
-
listen() is a blocking call. It won't return until the server stops. The server keeps running until you press Ctrl+C in your terminal or call svr.stop() from another thread.
-
Routing
-
Routing is the heart of any server. It's how you tell cpp-httplib: when a request comes in for this URL with this HTTP method, run this code.
svr.Get() registers a handler for GET requests. The first argument is the path, the second is the handler function. When a GET request arrives at /hi, your lambda runs.
-
There's a method for each HTTP verb.
-
-svr.Get("/path", handler); // GET
-svr.Post("/path", handler); // POST
-svr.Put("/path", handler); // PUT
-svr.Delete("/path", handler); // DELETE
-
-
-svr.Get("/path", handler); // GET
-svr.Post("/path", handler); // POST
-svr.Put("/path", handler); // PUT
-svr.Delete("/path", handler); // DELETE
-
-
-
The handler signature is (const httplib::Request &req, httplib::Response &res). You can use auto to keep it short.
-
-svr.Get("/hi", [](const auto &req, auto &res) {
- res.set_content("Hello!", "text/plain");
-});
-
-
-svr.Get("/hi", [](const auto &req, auto &res) {
- res.set_content("Hello!", "text/plain");
-});
-
-
-
The handler only runs when the path matches. Requests to unregistered paths automatically return 404.
-
The Request Object
-
The first parameter req gives you everything the client sent.
-
Body
-
req.body holds the request body as a std::string.
-
-svr.Post("/post", [](const auto &req, auto &res) {
-// Echo the body back to the client
- res.set_content(req.body, "text/plain");
-});
-
-
-svr.Post("/post", [](const auto &req, auto &res) {
-// Echo the body back to the client
- res.set_content(req.body, "text/plain");
-});
-
-
-
Headers
-
Use req.get_header_value() to read a request header.
-
-svr.Get("/check", [](const auto &req, auto &res) {
-auto auth = req.get_header_value("Authorization");
- res.set_content("Auth: " + auth, "text/plain");
-});
-
-
-svr.Get("/check", [](const auto &req, auto &res) {
-auto auth = req.get_header_value("Authorization");
- res.set_content("Auth: " + auth, "text/plain");
-});
-
-
-
Query Parameters and Form Data
-
req.get_param_value() retrieves a parameter by name. It works for both GET query parameters and POST form data.
-
-svr.Get("/search", [](const auto &req, auto &res) {
-auto q = req.get_param_value("q");
- res.set_content("Query: " + q, "text/plain");
-});
-
-
-svr.Get("/search", [](const auto &req, auto &res) {
-auto q = req.get_param_value("q");
- res.set_content("Query: " + q, "text/plain");
-});
-
-
-
A request to /search?q=cpp-httplib gives you "cpp-httplib" for q.
-
To loop over all parameters, use req.params.
-
-svr.Post("/submit", [](const auto &req, auto &res) {
- std::string result;
-for (auto &[key, val] : req.params) {
- result += key + " = " + val + "\n";
- }
- res.set_content(result, "text/plain");
-});
-
-
-svr.Post("/submit", [](const auto &req, auto &res) {
- std::string result;
-for (auto &[key, val] : req.params) {
- result += key + " = " + val + "\n";
- }
- res.set_content(result, "text/plain");
-});
-
-
-
File Uploads
-
Files uploaded via multipart form data are available through req.form.get_file().
-
-svr.Post("/upload", [](const auto &req, auto &res) {
-auto f = req.form.get_file("file");
-auto content = f.filename + " (" + std::to_string(f.content.size()) + " bytes)";
- res.set_content(content, "text/plain");
-});
-
-
-svr.Post("/upload", [](const auto &req, auto &res) {
-auto f = req.form.get_file("file");
-auto content = f.filename + " (" + std::to_string(f.content.size()) + " bytes)";
- res.set_content(content, "text/plain");
-});
-
-
-
f.filename gives you the filename, and f.content gives you the file data.
-
Path Parameters
-
Sometimes you want to capture part of the URL as a variable -- for example, the 42 in /users/42. Use the :param syntax to do that.
-
-svr.Get("/users/:id", [](const auto &req, auto &res) {
-auto id = req.path_params.at("id");
- res.set_content("User ID: " + id, "text/plain");
-});
-
-
-svr.Get("/users/:id", [](const auto &req, auto &res) {
-auto id = req.path_params.at("id");
- res.set_content("User ID: " + id, "text/plain");
-});
-
-
-
A request to /users/42 gives you "42" from req.path_params.at("id"). /users/100 gives you "100".
You can also write a regular expression directly in the path instead of :param. Capture group values are available via req.matches, which is a std::smatch.
-
-// Only accept numeric IDs
-svr.Get(R"(/files/(\d+))", [](const auto &req, auto &res) {
-auto id = req.matches[1]; // First capture group
- res.set_content("File ID: " + std::string(id), "text/plain");
-});
-
-
-// Only accept numeric IDs
-svr.Get(R"(/files/(\d+))", [](const auto &req, auto &res) {
-auto id = req.matches[1]; // First capture group
- res.set_content("File ID: " + std::string(id), "text/plain");
-});
-
-
-
/files/42 matches, but /files/abc doesn't. This is handy when you want to constrain what values are accepted.
-
Building a Response
-
The second parameter res is how you send data back to the client.
-
Body and Content-Type
-
res.set_content() sets the body and Content-Type. That's all you need for a 200 response.
-
-svr.Get("/hi", [](const auto &req, auto &res) {
- res.set_content("Hello!", "text/plain");
-});
-
-
-svr.Get("/hi", [](const auto &req, auto &res) {
- res.set_content("Hello!", "text/plain");
-});
-
-
-
Status Code
-
To return a different status code, assign to res.status.
-
-svr.Get("/not-found", [](const auto &req, auto &res) {
- res.status = 404;
- res.set_content("Not found", "text/plain");
-});
-
-
-svr.Get("/not-found", [](const auto &req, auto &res) {
- res.status = 404;
- res.set_content("Not found", "text/plain");
-});
-
-
-
Response Headers
-
Add response headers with res.set_header().
-
-svr.Get("/with-header", [](const auto &req, auto &res) {
- res.set_header("X-Custom", "my-value");
- res.set_content("Hello!", "text/plain");
-});
-
-
-svr.Get("/with-header", [](const auto &req, auto &res) {
- res.set_header("X-Custom", "my-value");
- res.set_content("Hello!", "text/plain");
-});
-
-
-
Walking Through the Test Server
-
Now let's use what we've learned to read through the test server from the previous chapter.
-
GET /hi
-
-svr.Get("/hi", [](const auto &, auto &res) {
- res.set_content("Hello!", "text/plain");
-});
-
-
-svr.Get("/hi", [](const auto &, auto &res) {
- res.set_content("Hello!", "text/plain");
-});
-
-
-
The simplest possible handler. We don't need any information from the request, so the req parameter is left unnamed. It just returns "Hello!".
-
GET /search
-
-svr.Get("/search", [](const auto &req, auto &res) {
-auto q = req.get_param_value("q");
- res.set_content("Query: " + q, "text/plain");
-});
-
-
-svr.Get("/search", [](const auto &req, auto &res) {
-auto q = req.get_param_value("q");
- res.set_content("Query: " + q, "text/plain");
-});
-
-
-
req.get_param_value("q") pulls out the query parameter q. A request to /search?q=cpp-httplib returns "Query: cpp-httplib".
-
POST /post
-
-svr.Post("/post", [](const auto &req, auto &res) {
- res.set_content(req.body, "text/plain");
-});
-
-
-svr.Post("/post", [](const auto &req, auto &res) {
- res.set_content(req.body, "text/plain");
-});
-
-
-
An echo server. Whatever body the client sends, req.body holds it, and we send it straight back.
-
POST /submit
-
-svr.Post("/submit", [](const auto &req, auto &res) {
- std::string result;
-for (auto &[key, val] : req.params) {
- result += key + " = " + val + "\n";
- }
- res.set_content(result, "text/plain");
-});
-
-
-svr.Post("/submit", [](const auto &req, auto &res) {
- std::string result;
-for (auto &[key, val] : req.params) {
- result += key + " = " + val + "\n";
- }
- res.set_content(result, "text/plain");
-});
-
-
-
Loops over the form data in req.params using structured bindings (auto &[key, val]) to unpack each key-value pair.
-
POST /upload
-
-svr.Post("/upload", [](const auto &req, auto &res) {
-auto f = req.form.get_file("file");
-auto content = f.filename + " (" + std::to_string(f.content.size()) + " bytes)";
- res.set_content(content, "text/plain");
-});
-
-
-svr.Post("/upload", [](const auto &req, auto &res) {
-auto f = req.form.get_file("file");
-auto content = f.filename + " (" + std::to_string(f.content.size()) + " bytes)";
- res.set_content(content, "text/plain");
-});
-
-
-
Receives a file uploaded via multipart form data. req.form.get_file("file") fetches the field named "file", and we respond with the filename and size.
-
GET /users/:id
-
-svr.Get("/users/:id", [](const auto &req, auto &res) {
-auto id = req.path_params.at("id");
- res.set_content("User ID: " + id, "text/plain");
-});
-
-
-svr.Get("/users/:id", [](const auto &req, auto &res) {
-auto id = req.path_params.at("id");
- res.set_content("User ID: " + id, "text/plain");
-});
-
-
-
:id is the path parameter. req.path_params.at("id") retrieves its value. /users/42 gives you "42", /users/alice gives you "alice".
-
GET /files/(\d+)
-
-svr.Get(R"(/files/(\d+))", [](const auto &req, auto &res) {
-auto id = req.matches[1];
- res.set_content("File ID: " + std::string(id), "text/plain");
-});
-
-
-svr.Get(R"(/files/(\d+))", [](const auto &req, auto &res) {
-auto id = req.matches[1];
- res.set_content("File ID: " + std::string(id), "text/plain");
-});
-
-
-
The regex (\d+) matches numeric IDs only. /files/42 hits this handler, but /files/abc returns 404. req.matches[1] retrieves the first capture group.
-
Next Steps
-
You now have the full picture of how a server works. Routing, reading requests, building responses -- that's enough to build a real API server.
-
Next, let's look at serving static files. We'll build a server that delivers HTML and CSS.
cpp-httplib can serve static files too — HTML, CSS, images, you name it. No complicated configuration required. One call to set_mount_point() is all it takes.
-
The basics of set_mount_point
-
Let's jump right in. set_mount_point() maps a URL path to a local directory.
The first argument is the URL mount point. The second is the local directory path. In this example, requests to / are served from the ./html directory.
-
Let's try it out. First, create an html directory and add an index.html file.
-
-mkdir html
-
-
-mkdir html
-
-
-<!DOCTYPE html>
-<html>
-<head><title>My Page</title></head>
-<body>
- <h1>Hello from cpp-httplib!</h1>
- <p>This is a static file.</p>
-</body>
-</html>
-
-
-<!DOCTYPE html>
-<html>
-<head><title>My Page</title></head>
-<body>
- <h1>Hello from cpp-httplib!</h1>
- <p>This is a static file.</p>
-</body>
-</html>
-
-
-
Compile and start the server.
-
-g++ -std=c++17 -o server server.cpp -pthread
-./server
-
-
-g++ -std=c++17 -o server server.cpp -pthread
-./server
-
-
-
Open http://localhost:8080 in your browser. You should see the contents of html/index.html. Visiting http://localhost:8080/index.html returns the same page.
-
You can also access it with the client code from the previous chapter, or with curl.
-
-httplib::Client cli("http://localhost:8080");
-auto res = cli.Get("/");
-if (res) {
- std::cout << res->body << std::endl; // HTML is displayed
-}
-
-
-httplib::Client cli("http://localhost:8080");
-auto res = cli.Get("/");
-if (res) {
- std::cout << res->body << std::endl; // HTML is displayed
-}
-
-
-curl http://localhost:8080
-
-
-curl http://localhost:8080
-
-
-
Multiple mount points
-
You can call set_mount_point() as many times as you like. Each URL path gets its own directory.
With this in place, the browser caches served files for one hour.
-
A Dockerfile for your static file server
-
The cpp-httplib repository includes a Dockerfile built for static file serving. We also publish a pre-built image on Docker Hub, so you can get up and running with a single command.
Everything in your ./my-site directory gets served on port 8080. The access log follows the same format as NGINX, so you can see exactly what's happening.
-
What's next
-
You can now serve static files. A web server that delivers HTML, CSS, and JavaScript — built with this little code.
-
Next, let's encrypt your connections with HTTPS. We'll start by setting up a TLS library.
Compile and run it. If you see Status: 200, your setup is complete.
-
Other TLS Backends
-
cpp-httplib also supports Mbed TLS and wolfSSL in addition to OpenSSL. You can switch between them just by changing the macro definition and linked libraries.
-
Backend
Macro
Libraries to link
-
OpenSSL
CPPHTTPLIB_OPENSSL_SUPPORT
libssl, libcrypto
-
Mbed TLS
CPPHTTPLIB_MBEDTLS_SUPPORT
libmbedtls, libmbedx509, libmbedcrypto
-
wolfSSL
CPPHTTPLIB_WOLFSSL_SUPPORT
libwolfssl
-
-
This tour assumes OpenSSL, but the API is the same regardless of which backend you choose.
-
Next Step
-
You're all set with TLS. Next, let's send a request to an HTTPS site.
In the previous chapter, you set up OpenSSL. Now let's put it to use with an HTTPS client. You can use the same httplib::Client from Chapter 2. Just pass a URL with the https:// scheme to the constructor.
In Chapter 2, you wrote httplib::Client cli("http://localhost:8080"). All you need to change is the scheme to https://. Every API you learned in Chapter 2 -- Get(), Post(), and so on -- works exactly the same way.
-
-curl https://nghttp2.org/
-
-
-curl https://nghttp2.org/
-
-
-
Specifying a Port
-
The default port for HTTPS is 443. If you need a different port, include it in the URL.
-
-httplib::Client cli("https://localhost:8443");
-
-
-httplib::Client cli("https://localhost:8443");
-
-
-
CA Certificate Verification
-
When connecting over HTTPS, httplib::Client verifies the server certificate by default. It only connects to servers whose certificate was issued by a trusted CA (Certificate Authority).
-
CA certificates are loaded automatically from the Keychain on macOS, the system CA certificate store on Linux, and the Windows certificate store on Windows. In most cases, no extra configuration is needed.
-
Specifying a CA Certificate File
-
On some environments, the system CA certificates may not be found. In that case, use set_ca_cert_path() to specify the path directly.
-
-httplib::Client cli("https://nghttp2.org");
-cli.set_ca_cert_path("/etc/ssl/certs/ca-certificates.crt");
-
-auto res = cli.Get("/");
-
-
-httplib::Client cli("https://nghttp2.org");
-cli.set_ca_cert_path("/etc/ssl/certs/ca-certificates.crt");
-
-auto res = cli.Get("/");
-
In the previous chapter, you used an HTTPS client. Now let's set up your own HTTPS server. Just swap httplib::Server from Chapter 3 with httplib::SSLServer.
-
A TLS server needs a server certificate and a private key, though. Let's get those ready first.
-
Creating a Self-Signed Certificate
-
For development and testing, a self-signed certificate works just fine. You can generate one quickly with an OpenSSL command.
Just pass the certificate and private key paths to the httplib::SSLServer constructor. The routing API is exactly the same as httplib::Server from Chapter 3.
-
Compile and start it up.
-
Testing It Out
-
With the server running, try accessing it with curl. Since we're using a self-signed certificate, add the -k option to skip certificate verification.
If you open https://localhost:8443 in a browser, you'll see a "This connection is not secure" warning. That's expected with a self-signed certificate. Just proceed past it.
-
Connecting from a Client
-
Let's connect using httplib::Client from the previous chapter. There are two ways to connect to a server with a self-signed certificate.
-
Option 1: Disable Certificate Verification
-
This is the quick and easy approach for development.
This way, only connections to the server with that specific certificate are allowed, preventing impersonation. Use this approach whenever possible, even in test environments.
-
Comparing Server and SSLServer
-
The httplib::Server API you learned in Chapter 3 works exactly the same with httplib::SSLServer. The only difference is the constructor.
-
httplib::Server
httplib::SSLServer
-
Constructor
No arguments
Certificate and private key paths
-
Protocol
HTTP
HTTPS
-
Port (convention)
8080
8443
-
Routing
Same
Same
-
-
To switch an HTTP server to HTTPS, just change the constructor.
-
Next Steps
-
Your HTTPS server is up and running. You now have the basics of both HTTP/HTTPS clients and servers covered.
-
Next, let's look at the WebSocket support that was recently added to cpp-httplib.
cpp-httplib supports WebSocket as well. Unlike HTTP request/response, WebSocket lets the server and client exchange messages in both directions. It's great for chat apps and real-time notifications.
-
Let's build an echo server and client right away.
-
Echo Server
-
Here's an echo server that sends back whatever message it receives.
You register a WebSocket handler with svr.WebSocket(). It works just like svr.Get() and svr.Post() from Chapter 3.
-
Inside the handler, ws.read(msg) waits for a message. When the connection closes, read() returns false, so the loop exits. ws.send(msg) sends a message back.
-
Connecting from a Client
-
Let's connect to the server using httplib::ws::WebSocketClient.
ws.send(const std::string &) — sends as a text message
-
ws.send(const char *, size_t) — sends as a binary message
-
-
The client-side API is the same.
-
Accessing Request Information
-
You can read HTTP request information from the handshake through the first argument req in the handler. This is handy for checking authentication tokens.
Great job finishing the Tour! You now have a solid grasp of the cpp-httplib basics. But there's a lot more to explore. Here's a quick overview of features we didn't cover in the Tour, organized by category.
-
Streaming API
-
When you're working with LLM streaming responses or downloading large files, you don't want to load the entire response into memory. Use stream::Get() to process data chunk by chunk.
On the server side, you have set_content_provider() and set_chunked_content_provider(). Use the former when you know the size, and the latter when you don't.
-
-// With known size (sets Content-Length)
-svr.Get("/file", [](const auto &, auto &res) {
-auto size = get_file_size("large.bin");
- res.set_content_provider(size, "application/octet-stream",
- [](size_t offset, size_t length, httplib::DataSink &sink) {
-// Send 'length' bytes starting from 'offset'
-return true;
- });
-});
-
-// Unknown size (Chunked Transfer Encoding)
-svr.Get("/stream", [](const auto &, auto &res) {
- res.set_chunked_content_provider("text/plain",
- [](size_t offset, httplib::DataSink &sink) {
- sink.write("chunk\n", 6);
-return true; // Return false to finish
- });
-});
-
-
-// With known size (sets Content-Length)
-svr.Get("/file", [](const auto &, auto &res) {
-auto size = get_file_size("large.bin");
- res.set_content_provider(size, "application/octet-stream",
- [](size_t offset, size_t length, httplib::DataSink &sink) {
-// Send 'length' bytes starting from 'offset'
-return true;
- });
-});
-
-// Unknown size (Chunked Transfer Encoding)
-svr.Get("/stream", [](const auto &, auto &res) {
- res.set_chunked_content_provider("text/plain",
- [](size_t offset, httplib::DataSink &sink) {
- sink.write("chunk\n", 6);
-return true; // Return false to finish
- });
-});
-
-
-
For uploading large files, make_file_provider() comes in handy. It streams the file instead of loading it all into memory.
You can hook into request processing before and after handlers run.
-
-svr.set_pre_routing_handler([](const auto &req, auto &res) {
-// Runs before every request
-return httplib::Server::HandlerResponse::Unhandled; // Continue to normal routing
-});
-
-svr.set_post_routing_handler([](const auto &req, auto &res) {
-// Runs after the response is sent
- res.set_header("X-Server", "cpp-httplib");
-});
-
-
-svr.set_pre_routing_handler([](const auto &req, auto &res) {
-// Runs before every request
-return httplib::Server::HandlerResponse::Unhandled; // Continue to normal routing
-});
-
-svr.set_post_routing_handler([](const auto &req, auto &res) {
-// Runs after the response is sent
- res.set_header("X-Server", "cpp-httplib");
-});
-
-
-
Use req.user_data to pass data from middleware to handlers. This is useful for sharing things like decoded auth tokens.
-
-svr.set_pre_routing_handler([](const auto &req, auto &res) {
- req.user_data["auth_user"] = std::string("alice");
-return httplib::Server::HandlerResponse::Unhandled;
-});
-
-svr.Get("/me", [](const auto &req, auto &res) {
-auto user = std::any_cast<std::string>(req.user_data.at("auth_user"));
- res.set_content("Hello, " + user, "text/plain");
-});
-
-
-svr.set_pre_routing_handler([](const auto &req, auto &res) {
- req.user_data["auth_user"] = std::string("alice");
-return httplib::Server::HandlerResponse::Unhandled;
-});
-
-svr.Get("/me", [](const auto &req, auto &res) {
-auto user = std::any_cast<std::string>(req.user_data.at("auth_user"));
- res.set_content("Hello, " + user, "text/plain");
-});
-
-
-
You can also customize error and exception handlers.
-
-svr.set_error_handler([](const auto &req, auto &res) {
- res.set_content("Custom Error Page", "text/html");
-});
-
-svr.set_exception_handler([](const auto &req, auto &res, std::exception_ptr ep) {
- res.status = 500;
- res.set_content("Internal Server Error", "text/plain");
-});
-
-
-svr.set_error_handler([](const auto &req, auto &res) {
- res.set_content("Custom Error Page", "text/html");
-});
-
-svr.set_exception_handler([](const auto &req, auto &res, std::exception_ptr ep) {
- res.status = 500;
- res.set_content("Internal Server Error", "text/plain");
-});
-
-
-
Logging
-
You can set a logger on both the server and the client.
This is a step-by-step tutorial that walks you through the basics of cpp-httplib. Each chapter builds on the previous one, so please read them in order starting from Chapter 1.
-
-
Getting Started — Get httplib.h and build a Hello World server
-
Basic Client — Send GET/POST requests and use path parameters
-
Basic Server — Routing, path parameters, and building responses
-
-
-
-
diff --git a/docs/js/main.js b/docs/js/main.js
deleted file mode 100644
index 0f2a89f..0000000
--- a/docs/js/main.js
+++ /dev/null
@@ -1,297 +0,0 @@
-// Language selector
-(function () {
- var btn = document.querySelector('.lang-btn');
- var popup = document.querySelector('.lang-popup');
- if (!btn || !popup) return;
-
- btn.addEventListener('click', function (e) {
- e.stopPropagation();
- popup.classList.toggle('open');
- });
-
- document.addEventListener('click', function () {
- popup.classList.remove('open');
- });
-
- popup.addEventListener('click', function (e) {
- var link = e.target.closest('[data-lang]');
- if (!link) return;
- e.preventDefault();
- var lang = link.getAttribute('data-lang');
- localStorage.setItem('preferred-lang', lang);
- var basePath = document.documentElement.getAttribute('data-base-path') || '';
- var path = window.location.pathname;
- // Strip base path prefix, replace lang, then re-add base path
- var pathWithoutBase = path.slice(basePath.length);
- var newPath = basePath + pathWithoutBase.replace(/^\/[a-z]{2}\//, '/' + lang + '/');
- window.location.href = newPath;
- });
-})();
-
-// Theme toggle
-(function () {
- var btn = document.querySelector('.theme-toggle');
- if (!btn) return;
-
- // Feather Icons: sun (light mode) and moon (dark mode)
- var sunSVG = '';
- var moonSVG = '';
-
- function getTheme() {
- var stored = localStorage.getItem('preferred-theme');
- if (stored) return stored;
- return window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
- }
-
- function applyTheme(theme) {
- if (theme === 'light') {
- document.documentElement.setAttribute('data-theme', 'light');
- } else {
- document.documentElement.removeAttribute('data-theme');
- }
- btn.innerHTML = theme === 'light' ? sunSVG : moonSVG;
- }
-
- applyTheme(getTheme());
-
- btn.addEventListener('click', function () {
- var current = getTheme();
- var next = current === 'dark' ? 'light' : 'dark';
- localStorage.setItem('preferred-theme', next);
- applyTheme(next);
- });
-})();
-
-// Mobile sidebar toggle
-(function () {
- var toggle = document.querySelector('.sidebar-toggle');
- var sidebar = document.querySelector('.sidebar');
- if (!toggle || !sidebar) return;
-
- toggle.addEventListener('click', function () {
- sidebar.classList.toggle('open');
- });
-
- document.addEventListener('click', function (e) {
- if (!sidebar.contains(e.target) && e.target !== toggle) {
- sidebar.classList.remove('open');
- }
- });
-})();
-
-// Site search (⌘K / Ctrl+K)
-(function () {
- var overlay = document.getElementById('search-overlay');
- var input = document.getElementById('search-input');
- var resultsList = document.getElementById('search-results');
- if (!overlay || !input || !resultsList) return;
-
- var searchBtn = document.querySelector('.search-btn');
- var pagesData = null; // cached pages-data.json
- var activeIndex = -1;
-
- function getCurrentLang() {
- return document.documentElement.getAttribute('lang') || 'en';
- }
-
- function getBasePath() {
- return document.documentElement.getAttribute('data-base-path') || '';
- }
-
- function openSearch() {
- overlay.classList.add('open');
- input.value = '';
- resultsList.innerHTML = '';
- activeIndex = -1;
- input.focus();
- loadPagesData();
- }
-
- function closeSearch() {
- overlay.classList.remove('open');
- input.value = '';
- resultsList.innerHTML = '';
- activeIndex = -1;
- }
-
- function loadPagesData() {
- if (pagesData) return;
- var basePath = getBasePath();
- fetch(basePath + '/pages-data.json')
- .then(function (res) { return res.json(); })
- .then(function (data) { pagesData = data; })
- .catch(function () { pagesData = []; });
- }
-
- function escapeRegExp(s) {
- return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
- }
-
- function highlightText(text, query) {
- if (!query) return text;
- var escaped = escapeRegExp(query);
- var re = new RegExp('(' + escaped + ')', 'gi');
- return text.replace(re, '$1');
- }
-
- function buildSnippet(body, query) {
- if (!query || !body) return '';
- var lower = body.toLowerCase();
- var idx = lower.indexOf(query.toLowerCase());
- var start, end, snippet;
- if (idx === -1) {
- snippet = body.substring(0, 120);
- } else {
- start = Math.max(0, idx - 40);
- end = Math.min(body.length, idx + query.length + 80);
- snippet = (start > 0 ? '...' : '') + body.substring(start, end) + (end < body.length ? '...' : '');
- }
- return highlightText(snippet, query);
- }
-
- function search(query) {
- if (!pagesData || !query) {
- resultsList.innerHTML = '';
- activeIndex = -1;
- return;
- }
-
- var lang = getCurrentLang();
- var q = query.toLowerCase();
-
- // Score and filter
- var scored = [];
- for (var i = 0; i < pagesData.length; i++) {
- var page = pagesData[i];
- if (page.lang !== lang) continue;
-
- var score = 0;
- var titleLower = page.title.toLowerCase();
- var bodyLower = (page.body || '').toLowerCase();
-
- if (titleLower.indexOf(q) !== -1) {
- score += 10;
- // Bonus for exact title match
- if (titleLower === q) score += 5;
- }
- if (bodyLower.indexOf(q) !== -1) {
- score += 3;
- }
- if (page.section.toLowerCase().indexOf(q) !== -1) {
- score += 1;
- }
-
- if (score > 0) {
- scored.push({ page: page, score: score });
- }
- }
-
- // Sort by score descending
- scored.sort(function (a, b) { return b.score - a.score; });
-
- // Limit results
- var results = scored.slice(0, 20);
-
- if (results.length === 0) {
- resultsList.innerHTML = '
No results found.
';
- activeIndex = -1;
- return;
- }
-
- var html = '';
- for (var j = 0; j < results.length; j++) {
- var r = results[j];
- var snippet = buildSnippet(r.page.body, query);
- html += '
'
- + '
' + highlightText(r.page.title, query) + '
'
- + (snippet ? '
' + snippet + '
' : '')
- + '
';
- }
- resultsList.innerHTML = html;
- activeIndex = -1;
- }
-
- function setActive(index) {
- var items = resultsList.querySelectorAll('li[data-url]');
- if (items.length === 0) return;
- // Remove previous active
- for (var i = 0; i < items.length; i++) {
- items[i].classList.remove('active');
- }
- if (index < 0) index = items.length - 1;
- if (index >= items.length) index = 0;
- activeIndex = index;
- items[activeIndex].classList.add('active');
- items[activeIndex].scrollIntoView({ block: 'nearest' });
- }
-
- function navigateToActive() {
- var items = resultsList.querySelectorAll('li[data-url]');
- if (activeIndex >= 0 && activeIndex < items.length) {
- var url = items[activeIndex].getAttribute('data-url');
- if (url) {
- closeSearch();
- window.location.href = url;
- }
- }
- }
-
- // Event: search button
- if (searchBtn) {
- searchBtn.addEventListener('click', function (e) {
- e.stopPropagation();
- openSearch();
- });
- }
-
- // Use capture phase to intercept keys before browser default behavior
- // (e.g. ESC clearing input text in some browsers)
- document.addEventListener('keydown', function (e) {
- if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
- e.preventDefault();
- overlay.classList.contains('open') ? closeSearch() : openSearch();
- return;
- }
- if (!overlay.classList.contains('open')) return;
- if (e.key === 'Escape') {
- e.preventDefault();
- closeSearch();
- } else if (e.key === 'ArrowDown') {
- e.preventDefault();
- setActive(activeIndex + 1);
- } else if (e.key === 'ArrowUp') {
- e.preventDefault();
- setActive(activeIndex - 1);
- } else if (e.key === 'Enter') {
- e.preventDefault();
- navigateToActive();
- }
- }, true); // capture phase
-
- // Event: click overlay background to close
- overlay.addEventListener('click', function (e) {
- if (e.target === overlay) {
- closeSearch();
- }
- });
-
- // Event: click result item
- resultsList.addEventListener('click', function (e) {
- var li = e.target.closest('li[data-url]');
- if (!li) return;
- var url = li.getAttribute('data-url');
- if (url) {
- closeSearch();
- window.location.href = url;
- }
- });
-
- // Event: input for live search
- var debounceTimer = null;
- input.addEventListener('input', function () {
- clearTimeout(debounceTimer);
- debounceTimer = setTimeout(function () {
- search(input.value.trim());
- }, 150);
- });
-})();
diff --git a/docs/pages-data.json b/docs/pages-data.json
deleted file mode 100644
index aa9b798..0000000
--- a/docs/pages-data.json
+++ /dev/null
@@ -1 +0,0 @@
-[{"title":"Cookbook","url":"/cpp-httplib/en/cookbook/","lang":"en","section":"cookbook","body":"This section is under construction. Check back soon for a collection of recipes organized by topic."},{"title":"cpp-httplib","url":"/cpp-httplib/en/","lang":"en","section":"","body":"cpp-httplib is an HTTP/HTTPS library for C++. Just copy a single header file, httplib.h , and you're ready to go. When you need a quick HTTP server or client in C++, you want something that just works. That's exactly why I built cpp-httplib. You can start writing both servers and clients in just a few lines of code. The API uses a lambda-based design that feels natural. It runs anywhere you have a C++11 or later compiler. Windows, macOS, Linux — use whatever environment you already have. HTTPS w"},{"title":"Static File Server","url":"/cpp-httplib/en/tour/04-static-file-server/","lang":"en","section":"tour","body":"cpp-httplib can serve static files too — HTML, CSS, images, you name it. No complicated configuration required. One call to set_mount_point() is all it takes. The basics of set_mount_point Let's jump right in. set_mount_point() maps a URL path to a local directory. #include " httplib.h " #include < iostream > int main () { httplib::Server svr; svr. set_mount_point (" / ", " ./html "); std::cout << " Listening on port 8080... " << std::end"},{"title":"Getting Started","url":"/cpp-httplib/en/tour/01-getting-started/","lang":"en","section":"tour","body":"All you need to get started with cpp-httplib is httplib.h and a C++ compiler. Let's download the file and get a Hello World server running. Getting httplib.h You can download it directly from GitHub. Always use the latest version. curl -LO https://github.com/yhirose/cpp-httplib/raw/refs/tags/latest/httplib.h Place the downloaded httplib.h in your project directory and you're good to go. Setting Up Your Compiler OS Development Environment Setup macOS Apple Clang Xcode Command Line Tools ( xcode-s"},{"title":"Basic Server","url":"/cpp-httplib/en/tour/03-basic-server/","lang":"en","section":"tour","body":"In the previous chapter, you sent requests from a client to a test server. Now let's walk through how that server actually works. Starting the Server Once you've registered your routes, call svr.listen() to start the server. svr. listen (" 0.0.0.0 ", 8080 ); The first argument is the host, and the second is the port. \"0.0.0.0\" listens on all network interfaces. Use \"127.0.0.1\" if you want to accept connections from your own machine only. listen() is a blocking call. It won't return unt"},{"title":"Basic Client","url":"/cpp-httplib/en/tour/02-basic-client/","lang":"en","section":"tour","body":"cpp-httplib isn't just for servers -- it also comes with a full HTTP client. Let's use httplib::Client to send GET and POST requests. Preparing a Test Server To try out the client, you need a server that accepts requests. Save the following code, then compile and run it the same way you did in the previous chapter. We'll cover the server details in the next chapter. #include " httplib.h " #include < iostream > int main () { httplib::Server svr; svr. Get (" /hi ", []( co"},{"title":"HTTPS Client","url":"/cpp-httplib/en/tour/06-https-client/","lang":"en","section":"tour","body":"In the previous chapter, you set up OpenSSL. Now let's put it to use with an HTTPS client. You can use the same httplib::Client from Chapter 2. Just pass a URL with the https:// scheme to the constructor. GET Request Let's try accessing a real HTTPS site. #define CPPHTTPLIB_OPENSSL_SUPPORT #include " httplib.h " #include < iostream > int main () { httplib::Client cli (" https://nghttp2.org "); auto res = cli. Get (" / "); if (res) { std::cout << res->"},{"title":"A Tour of cpp-httplib","url":"/cpp-httplib/en/tour/","lang":"en","section":"tour","body":"This is a step-by-step tutorial that walks you through the basics of cpp-httplib. Each chapter builds on the previous one, so please read them in order starting from Chapter 1. Getting Started — Get httplib.h and build a Hello World server Basic Client — Send GET/POST requests and use path parameters Basic Server — Routing, path parameters, and building responses Static File Server — Serve static files TLS Setup — Set up OpenSSL / mbedTLS HTTPS Client — Make requests to HTTPS sites HTTPS Server "},{"title":"What's Next","url":"/cpp-httplib/en/tour/09-whats-next/","lang":"en","section":"tour","body":"Great job finishing the Tour! You now have a solid grasp of the cpp-httplib basics. But there's a lot more to explore. Here's a quick overview of features we didn't cover in the Tour, organized by category. Streaming API When you're working with LLM streaming responses or downloading large files, you don't want to load the entire response into memory. Use stream::Get() to process data chunk by chunk. httplib::Client cli (" http://localhost:11434 "); auto result = httplib::stream::Get ("},{"title":"TLS Setup","url":"/cpp-httplib/en/tour/05-tls-setup/","lang":"en","section":"tour","body":"So far we've been using plain HTTP, but in the real world, HTTPS is the norm. To use HTTPS with cpp-httplib, you need a TLS library. In this tour, we'll use OpenSSL. It's the most widely used option, and you'll find plenty of resources online. Installing OpenSSL Install it for your OS. OS How to install macOS Homebrew ( brew install openssl ) Ubuntu / Debian sudo apt install libssl-dev Windows vcpkg ( vcpkg install openssl ) Compile Options To enable TLS, define the CPPHTTPLIB_OPENSSL_SUPPORT ma"},{"title":"HTTPS Server","url":"/cpp-httplib/en/tour/07-https-server/","lang":"en","section":"tour","body":"In the previous chapter, you used an HTTPS client. Now let's set up your own HTTPS server. Just swap httplib::Server from Chapter 3 with httplib::SSLServer . A TLS server needs a server certificate and a private key, though. Let's get those ready first. Creating a Self-Signed Certificate For development and testing, a self-signed certificate works just fine. You can generate one quickly with an OpenSSL command. openssl req -x509 -noenc -keyout key.pem -out cert.pem -subj /CN=localhost This creat"},{"title":"WebSocket","url":"/cpp-httplib/en/tour/08-websocket/","lang":"en","section":"tour","body":"cpp-httplib supports WebSocket as well. Unlike HTTP request/response, WebSocket lets the server and client exchange messages in both directions. It's great for chat apps and real-time notifications. Let's build an echo server and client right away. Echo Server Here's an echo server that sends back whatever message it receives. #include " httplib.h " #include < iostream > int main () { httplib::Server svr; svr. WebSocket (" /ws ", []( const httplib::Request &, httpli"},{"title":"Cookbook","url":"/cpp-httplib/ja/cookbook/","lang":"ja","section":"cookbook","body":"This section is under construction. Check back soon for a collection of recipes organized by topic."},{"title":"cpp-httplib","url":"/cpp-httplib/ja/","lang":"ja","section":"","body":"cpp-httplib は、C++用のHTTP/HTTPSライブラリです。 httplib.h というヘッダーファイルを1枚コピーするだけで使えます。 C++でちょっとしたHTTPサーバーやクライアントが必要になったとき、すぐに動くものが欲しいですよね。cpp-httplibはまさにそのために作られました。サーバーもクライアントも、数行のコードで書き始められます。 APIはラムダ式をベースにした直感的な設計で、C++11以降のコンパイラーがあればどこでも動きます。Windows、macOS、Linux — お使いの環境をそのまま使えます。 HTTPSも使えます。OpenSSLやmbedTLSをリンクするだけで、サーバー・クライアントの両方がTLSに対応します。Content-Encoding(gzip, brotli等)、ファイルアップロードなど、実際の開発で必要になる機能もひと通り揃っています。WebSocketもサポートしています。 内部的にはブロッキングI/Oとスレッドプールを使っています。大量の同時接続を捌くような用途には向きませんが、APIサーバーやツールの組み込みHTTP、"},{"title":"Static File Server","url":"/cpp-httplib/ja/tour/04-static-file-server/","lang":"ja","section":"tour","body":"cpp-httplibは、HTMLやCSS、画像ファイルなどの静的ファイルも配信できます。面倒な設定は要りません。 set_mount_point() を1行呼ぶだけです。 set_mount_point の基本 さっそくやってみましょう。 set_mount_point() は、URLのパスとローカルディレクトリを紐づけます。 #include " httplib.h " #include < iostream > int main () { httplib::Server svr; svr. set_mount_point (" / ", " ./html "); std::cout << " Listening on port 8080... " << std::endl; svr. listen (" 0.0.0.0 ", 8080 ); } 第1引数がURLのマウントポイント、第2引数がローカルのディレクトリパスです。この例だと、 / へのリ"},{"title":"Getting Started","url":"/cpp-httplib/ja/tour/01-getting-started/","lang":"ja","section":"tour","body":"cpp-httplibを始めるのに必要なのは、 httplib.h とC++コンパイラーだけです。ファイルをダウンロードして、Hello Worldサーバーを動かすところまでやってみましょう。 httplib.h の入手 GitHubから直接ダウンロードできます。常に最新版を使ってください。 curl -LO https://github.com/yhirose/cpp-httplib/raw/refs/tags/latest/httplib.h ダウンロードした httplib.h をプロジェクトのディレクトリに置けば、準備完了です。 コンパイラーの準備 OS 開発環境 セットアップ macOS Apple Clang Xcode Command Line Tools ( xcode-select --install ) Ubuntu clang++ または g++ apt install clang または apt install g++ Windows MSVC Visual Studio 2022 以降(C++ コンポーネントを含めてインストール) Hello World サー"},{"title":"Basic Server","url":"/cpp-httplib/ja/tour/03-basic-server/","lang":"ja","section":"tour","body":"前章ではクライアントからリクエストを送りました。そのとき、テスト用サーバーを用意しましたね。この章では、あのサーバーの仕組みをひとつずつ紐解いていきます。 サーバーの起動 ルーティングを登録したら、最後に svr.listen() を呼んでサーバーを起動します。 svr. listen (" 0.0.0.0 ", 8080 ); 第1引数はホスト、第2引数はポート番号です。 \"0.0.0.0\" を指定すると、すべてのネットワークインターフェースでリクエストを受け付けます。自分のマシンからのアクセスだけに限定したいときは \"127.0.0.1\" を使います。 listen() はブロッキング呼び出しです。サーバーが停止するまで、この行から先には進みません。ターミナルで Ctrl+C を押すか、別スレッドから svr.stop() を呼ぶまでサーバーは動き続けます。 ルーティング サーバーの核になるのは「ルーティング」です。どのURLに、どのHTTPメソッドでアクセスされたら、何をするか。それを登録する仕組みです。 httplib::Server svr; svr. G"},{"title":"Basic Client","url":"/cpp-httplib/ja/tour/02-basic-client/","lang":"ja","section":"tour","body":"cpp-httplibはサーバーだけでなく、HTTPクライアント機能も備えています。 httplib::Client を使って、GETやPOSTリクエストを送ってみましょう。 テスト用サーバーの準備 クライアントの動作を確認するために、リクエストを受け付けるサーバーを用意します。次のコードを保存し、前章と同じ手順でコンパイル・実行してください。サーバーの詳しい解説は次章で行います。 #include " httplib.h " #include < iostream > int main () { httplib::Server svr; svr. Get (" /hi ", []( const auto &, auto &res) { res. set_content (" Hello! ", " text/plain "); }); svr. Get (" /search ", []( const auto &req, auto &res)"},{"title":"HTTPS Client","url":"/cpp-httplib/ja/tour/06-https-client/","lang":"ja","section":"tour","body":"前章でOpenSSLのセットアップが済んだので、さっそくHTTPSクライアントを使ってみましょう。2章で使った httplib::Client がそのまま使えます。コンストラクタに https:// 付きのURLを渡すだけです。 GETリクエスト 実在するHTTPSサイトにアクセスしてみましょう。 #define CPPHTTPLIB_OPENSSL_SUPPORT #include " httplib.h " #include < iostream > int main () { httplib::Client cli (" https://nghttp2.org "); auto res = cli. Get (" / "); if (res) { std::cout << res-> status << std::endl; // 200 std::cout << res-> body . substr ( 0 , 100 ) << std::end"},{"title":"A Tour of cpp-httplib","url":"/cpp-httplib/ja/tour/","lang":"ja","section":"tour","body":"cpp-httplibの基本を、順番に学んでいくチュートリアルです。各章は前の章の内容を踏まえて進む構成なので、1章から順に読んでください。 Getting Started — httplib.h の入手とHello Worldサーバー Basic Client — GET/POST・パスパラメーターのリクエスト送信 Basic Server — ルーティング、パスパラメーター、レスポンスの組み立て Static File Server — 静的ファイルの配信 TLS Setup — OpenSSL / mbedTLS のセットアップ HTTPS Client — HTTPSサイトへのリクエスト HTTPS Server — HTTPSサーバーの構築 WebSocket — WebSocket通信の基本 What's Next — さらなる機能の紹介"},{"title":"What's Next","url":"/cpp-httplib/ja/tour/09-whats-next/","lang":"ja","section":"tour","body":"Tourお疲れさまでした! cpp-httplibの基本はひと通り押さえましたね。でも、まだまだ便利な機能があります。Tourで取り上げなかった機能をカテゴリー別に紹介します。 Streaming API LLMのストリーミング応答や大きなファイルのダウンロードでは、レスポンス全体をメモリに載せたくないですよね。 stream::Get() を使えば、データをチャンクごとに処理できます。 httplib::Client cli (" http://localhost:11434 "); auto result = httplib::stream::Get (cli, " /api/generate "); if (result) { while (result. next ()) { std::cout. write (result. data (), result. size ()); } } Get() に content_receiver コールバックを渡す方法もあります。こちらはKeep-Aliveと併用できます。 httplib::Cl"},{"title":"TLS Setup","url":"/cpp-httplib/ja/tour/05-tls-setup/","lang":"ja","section":"tour","body":"ここまではHTTP(平文)でやってきましたが、実際のWebではHTTPS(暗号化通信)が当たり前ですよね。cpp-httplibでHTTPSを使うには、TLSライブラリが必要です。 このTourではOpenSSLを使います。最も広く使われていて、情報も豊富です。 OpenSSLのインストール お使いのOSに合わせてインストールしましょう。 OS インストール方法 macOS Homebrew ( brew install openssl ) Ubuntu / Debian sudo apt install libssl-dev Windows vcpkg ( vcpkg install openssl ) コンパイルオプション TLS機能を有効にするには、 CPPHTTPLIB_OPENSSL_SUPPORT マクロを定義してコンパイルします。前章までのコンパイルコマンドに、いくつかオプションが増えます。 # macOS (Homebrew) clang++ -std =c++17 -DCPPHTTPLIB_OPENSSL_SUPPORT \\ -I $ ( brew --prefix "},{"title":"HTTPS Server","url":"/cpp-httplib/ja/tour/07-https-server/","lang":"ja","section":"tour","body":"前章ではHTTPSクライアントを使いました。今度は自分でHTTPSサーバーを立ててみましょう。3章の httplib::Server を httplib::SSLServer に置き換えるだけです。 ただし、TLSサーバーにはサーバー証明書と秘密鍵が必要です。まずはそこから準備しましょう。 自己署名証明書の作成 開発やテスト用なら、自己署名証明書(いわゆるオレオレ証明書)で十分です。OpenSSLのコマンドでサクッと作れます。 openssl req -x509 -noenc -keyout key.pem -out cert.pem -subj /CN=localhost これで2つのファイルができます。 cert.pem — サーバー証明書 key.pem — 秘密鍵 最小のHTTPSサーバー 証明書ができたら、さっそくサーバーを書いてみましょう。 #define CPPHTTPLIB_OPENSSL_SUPPORT #include " httplib.h " #include < iostream > int main () { httplib:"},{"title":"WebSocket","url":"/cpp-httplib/ja/tour/08-websocket/","lang":"ja","section":"tour","body":"cpp-httplibはWebSocketにも対応しています。HTTPのリクエスト/レスポンスと違い、WebSocketはサーバーとクライアントが双方向にメッセージをやり取りできます。チャットやリアルタイム通知に便利です。 さっそく、エコーサーバーとクライアントを作ってみましょう。 エコーサーバー 受け取ったメッセージをそのまま返すエコーサーバーです。 #include " httplib.h " #include < iostream > int main () { httplib::Server svr; svr. WebSocket (" /ws ", []( const httplib::Request &, httplib::ws::WebSocket &ws) { std::string msg; while (ws. read (msg)) { ws. send (msg); // 受け取ったメッセージをそのまま返す } }); std::cout << " Listening on"}]
\ No newline at end of file