Top Related Projects
The C++ REST SDK is a Microsoft project for cloud-based client-server communication in native code using a modern asynchronous C++ API design. This project aims to help C++ developers connect to and interact with services.
Simple, secure & standards compliant web server for the most demanding of applications
A curated list of awesome C++ (or C) frameworks, libraries, resources, and shiny things. Inspired by awesome-... stuff.
HTTP and WebSocket built on Boost.Asio in C++11
C++ Requests: Curl for People, a spiritual port of Python Requests.
Quick Overview
cpp-httplib is a C++ header-only HTTP/HTTPS server and client library. It provides a simple and easy-to-use API for creating HTTP servers and making HTTP requests, supporting both synchronous and asynchronous operations.
Pros
- Header-only library, making it easy to integrate into projects
- Supports both HTTP and HTTPS
- Simple and intuitive API
- Cross-platform compatibility (Windows, macOS, Linux)
Cons
- Limited advanced features compared to more comprehensive networking libraries
- May not be suitable for high-performance, large-scale applications
- Lacks built-in support for WebSockets
Code Examples
- Creating a simple HTTP server:
#include <httplib.h>
int main() {
httplib::Server svr;
svr.Get("/", [](const httplib::Request&, httplib::Response& res) {
res.set_content("Hello, World!", "text/plain");
});
svr.listen("localhost", 8080);
}
- Making a GET request:
#include <httplib.h>
#include <iostream>
int main() {
httplib::Client cli("http://example.com");
auto res = cli.Get("/");
if (res && res->status == 200) {
std::cout << res->body << std::endl;
}
}
- Handling POST requests with JSON:
#include <httplib.h>
#include <nlohmann/json.hpp>
int main() {
httplib::Server svr;
svr.Post("/api/data", [](const httplib::Request& req, httplib::Response& res) {
auto json = nlohmann::json::parse(req.body);
// Process JSON data
res.set_content("{\"status\":\"success\"}", "application/json");
});
svr.listen("localhost", 8080);
}
Getting Started
- Download the
httplib.h
header file from the GitHub repository. - Include the header in your C++ project:
#include "httplib.h"
- If using HTTPS, make sure to define
CPPHTTPLIB_OPENSSL_SUPPORT
before including the header:#define CPPHTTPLIB_OPENSSL_SUPPORT #include "httplib.h"
- Compile your project with the appropriate flags (e.g.,
-std=c++11
or higher). - Link against OpenSSL libraries if using HTTPS support.
Competitor Comparisons
The C++ REST SDK is a Microsoft project for cloud-based client-server communication in native code using a modern asynchronous C++ API design. This project aims to help C++ developers connect to and interact with services.
Pros of cpprestsdk
- More comprehensive feature set, including support for WebSockets and OAuth
- Better suited for large-scale, enterprise-level applications
- Extensive documentation and Microsoft support
Cons of cpprestsdk
- Larger footprint and more dependencies
- Steeper learning curve due to its complexity
- Slower compilation times compared to cpp-httplib
Code Comparison
cpp-httplib:
#include <httplib.h>
int main() {
httplib::Server svr;
svr.Get("/", [](const httplib::Request&, httplib::Response& res) {
res.set_content("Hello, World!", "text/plain");
});
svr.listen("localhost", 8080);
}
cpprestsdk:
#include <cpprest/http_listener.h>
int main() {
web::http::experimental::listener::http_listener listener("http://localhost:8080");
listener.support(web::http::methods::GET, [](web::http::http_request request) {
request.reply(web::http::status_codes::OK, "Hello, World!");
});
listener.open().wait();
}
Both libraries provide HTTP server functionality, but cpprestsdk offers a more robust and feature-rich API at the cost of increased complexity. cpp-httplib is simpler and easier to use for basic HTTP operations, making it a good choice for smaller projects or when minimal dependencies are desired.
Simple, secure & standards compliant web server for the most demanding of applications
Pros of uWebSockets
- Higher performance and scalability, especially for WebSocket connections
- Lower memory footprint and CPU usage
- Support for both HTTP and WebSocket protocols in a single library
Cons of uWebSockets
- More complex API and steeper learning curve
- Less straightforward for simple HTTP server implementations
- Fewer built-in features for basic HTTP functionality
Code Comparison
uWebSockets:
uWS::App().get("/hello", [](auto *res, auto *req) {
res->end("Hello World!");
}).listen(3000, [](auto *token) {
if (token) {
std::cout << "Server listening on port 3000" << std::endl;
}
}).run();
cpp-httplib:
httplib::Server svr;
svr.Get("/hello", [](const httplib::Request&, httplib::Response& res) {
res.set_content("Hello World!", "text/plain");
});
svr.listen("localhost", 3000);
uWebSockets offers a more concise syntax for setting up routes and starting the server, while cpp-httplib provides a more straightforward approach for basic HTTP server functionality. uWebSockets is better suited for high-performance applications with WebSocket support, while cpp-httplib is easier to use for simple HTTP servers.
A curated list of awesome C++ (or C) frameworks, libraries, resources, and shiny things. Inspired by awesome-... stuff.
Pros of awesome-cpp
- Comprehensive collection of C++ libraries and resources
- Regularly updated with community contributions
- Covers a wide range of C++ topics and use cases
Cons of awesome-cpp
- Not a standalone library, requires additional setup and integration
- May overwhelm users with too many options for a specific task
Code comparison
Not applicable, as awesome-cpp is a curated list of resources and doesn't contain code to compare directly with cpp-httplib.
Pros of cpp-httplib
- Single-file, header-only HTTP/HTTPS server and client library
- Easy to integrate into existing C++ projects
- Supports both synchronous and asynchronous operations
Cons of cpp-httplib
- Limited to HTTP/HTTPS functionality
- May not be as feature-rich as some full-fledged networking libraries
Code comparison
cpp-httplib example:
#include <httplib.h>
int main() {
httplib::Server svr;
svr.Get("/hi", [](const httplib::Request&, httplib::Response& res) {
res.set_content("Hello World!", "text/plain");
});
svr.listen("localhost", 8080);
}
awesome-cpp doesn't have code to compare, as it's a curated list of resources.
HTTP and WebSocket built on Boost.Asio in C++11
Pros of Beast
- Part of the Boost ecosystem, offering integration with other Boost libraries
- More comprehensive feature set, including WebSocket support
- Better suited for high-performance, large-scale applications
Cons of Beast
- Steeper learning curve due to its complexity
- Requires Boost dependencies, increasing project size
- More verbose code for simple tasks compared to cpp-httplib
Code Comparison
Beast:
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/asio/ip/tcp.hpp>
namespace beast = boost::beast;
namespace http = beast::http;
namespace net = boost::asio;
using tcp = net::ip::tcp;
http::response<http::string_body> handle_request(http::request<http::string_body>&& req) {
// Handle request and return response
}
cpp-httplib:
#include <httplib.h>
int main() {
httplib::Server svr;
svr.Get("/", [](const httplib::Request&, httplib::Response& res) {
res.set_content("Hello, World!", "text/plain");
});
svr.listen("localhost", 8080);
}
Beast offers more control and flexibility but requires more setup code. cpp-httplib provides a simpler API for basic HTTP server functionality, making it easier to get started quickly.
C++ Requests: Curl for People, a spiritual port of Python Requests.
Pros of cpr
- More feature-rich, supporting advanced HTTP features like authentication, cookies, and proxies
- Better cross-platform support, including Windows, macOS, and Linux
- Extensive documentation and examples
Cons of cpr
- Larger dependency footprint due to reliance on libcurl
- Potentially slower compilation times compared to cpp-httplib
- More complex setup and integration process
Code Comparison
cpp-httplib:
#include <httplib.h>
int main() {
httplib::Client cli("http://example.com");
auto res = cli.Get("/");
if (res && res->status == 200) {
std::cout << res->body << std::endl;
}
}
cpr:
#include <cpr/cpr.h>
int main() {
auto r = cpr::Get(cpr::Url{"http://example.com"});
if (r.status_code == 200) {
std::cout << r.text << std::endl;
}
}
Both libraries offer simple HTTP requests, but cpr provides a more modern and intuitive API. cpp-httplib is lighter and easier to integrate, while cpr offers more advanced features at the cost of increased complexity and dependencies.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
cpp-httplib
A C++11 single-file header-only cross platform HTTP/HTTPS library.
It's extremely easy to setup. Just include the httplib.h file in your code!
[!IMPORTANT] This library uses 'blocking' socket I/O. If you are looking for a library with 'non-blocking' socket I/O, this is not the one that you want.
Simple examples
Server (Multi-threaded)
#define CPPHTTPLIB_OPENSSL_SUPPORT
#include "path/to/httplib.h"
// HTTP
httplib::Server svr;
// HTTPS
httplib::SSLServer svr;
svr.Get("/hi", [](const httplib::Request &, httplib::Response &res) {
res.set_content("Hello World!", "text/plain");
});
svr.listen("0.0.0.0", 8080);
Client
#define CPPHTTPLIB_OPENSSL_SUPPORT
#include "path/to/httplib.h"
// HTTP
httplib::Client cli("http://cpp-httplib-server.yhirose.repl.co");
// HTTPS
httplib::Client cli("https://cpp-httplib-server.yhirose.repl.co");
auto res = cli.Get("/hi");
res->status;
res->body;
SSL Support
SSL support is available with CPPHTTPLIB_OPENSSL_SUPPORT
. libssl
and libcrypto
should be linked.
[!NOTE] cpp-httplib currently supports only version 3.0 or later. Please see this page to get more information.
[!TIP] For macOS: cpp-httplib now can use system certs with
CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN
.CoreFoundation
andSecurity
should be linked with-framework
.
#define CPPHTTPLIB_OPENSSL_SUPPORT
#include "path/to/httplib.h"
// Server
httplib::SSLServer svr("./cert.pem", "./key.pem");
// Client
httplib::Client cli("https://localhost:1234"); // scheme + host
httplib::SSLClient cli("localhost:1234"); // host
httplib::SSLClient cli("localhost", 1234); // host, port
// Use your CA bundle
cli.set_ca_cert_path("./ca-bundle.crt");
// Disable cert verification
cli.enable_server_certificate_verification(false);
// Disable host verification
cli.enable_server_host_verification(false);
[!NOTE] When using SSL, it seems impossible to avoid SIGPIPE in all cases, since on some operating systems, SIGPIPE can only be suppressed on a per-message basis, but there is no way to make the OpenSSL library do so for its internal communications. If your program needs to avoid being terminated on SIGPIPE, the only fully general way might be to set up a signal handler for SIGPIPE to handle or ignore it yourself.
Server
#include <httplib.h>
int main(void)
{
using namespace httplib;
Server svr;
svr.Get("/hi", [](const Request& req, Response& res) {
res.set_content("Hello World!", "text/plain");
});
// Match the request path against a regular expression
// and extract its captures
svr.Get(R"(/numbers/(\d+))", [&](const Request& req, Response& res) {
auto numbers = req.matches[1];
res.set_content(numbers, "text/plain");
});
// Capture the second segment of the request path as "id" path param
svr.Get("/users/:id", [&](const Request& req, Response& res) {
auto user_id = req.path_params.at("id");
res.set_content(user_id, "text/plain");
});
// Extract values from HTTP headers and URL query params
svr.Get("/body-header-param", [](const Request& req, Response& res) {
if (req.has_header("Content-Length")) {
auto val = req.get_header_value("Content-Length");
}
if (req.has_param("key")) {
auto val = req.get_param_value("key");
}
res.set_content(req.body, "text/plain");
});
svr.Get("/stop", [&](const Request& req, Response& res) {
svr.stop();
});
svr.listen("localhost", 1234);
}
Post
, Put
, Delete
and Options
methods are also supported.
Bind a socket to multiple interfaces and any available port
int port = svr.bind_to_any_port("0.0.0.0");
svr.listen_after_bind();
Static File Server
// Mount / to ./www directory
auto ret = svr.set_mount_point("/", "./www");
if (!ret) {
// The specified base directory doesn't exist...
}
// Mount /public to ./www directory
ret = svr.set_mount_point("/public", "./www");
// Mount /public to ./www1 and ./www2 directories
ret = svr.set_mount_point("/public", "./www1"); // 1st order to search
ret = svr.set_mount_point("/public", "./www2"); // 2nd order to search
// Remove mount /
ret = svr.remove_mount_point("/");
// Remove mount /public
ret = svr.remove_mount_point("/public");
// User defined file extension and MIME type mappings
svr.set_file_extension_and_mimetype_mapping("cc", "text/x-c");
svr.set_file_extension_and_mimetype_mapping("cpp", "text/x-c");
svr.set_file_extension_and_mimetype_mapping("hh", "text/x-h");
The followings are built-in mappings:
Extension | MIME Type | Extension | MIME Type |
---|---|---|---|
css | text/css | mpga | audio/mpeg |
csv | text/csv | weba | audio/webm |
txt | text/plain | wav | audio/wave |
vtt | text/vtt | otf | font/otf |
html, htm | text/html | ttf | font/ttf |
apng | image/apng | woff | font/woff |
avif | image/avif | woff2 | font/woff2 |
bmp | image/bmp | 7z | application/x-7z-compressed |
gif | image/gif | atom | application/atom+xml |
png | image/png | application/pdf | |
svg | image/svg+xml | mjs, js | application/javascript |
webp | image/webp | json | application/json |
ico | image/x-icon | rss | application/rss+xml |
tif | image/tiff | tar | application/x-tar |
tiff | image/tiff | xhtml, xht | application/xhtml+xml |
jpeg, jpg | image/jpeg | xslt | application/xslt+xml |
mp4 | video/mp4 | xml | application/xml |
mpeg | video/mpeg | gz | application/gzip |
webm | video/webm | zip | application/zip |
mp3 | audio/mp3 | wasm | application/wasm |
[!WARNING] These static file server methods are not thread-safe.
File request handler
// The handler is called right before the response is sent to a client
svr.set_file_request_handler([](const Request &req, Response &res) {
...
});
Logging
svr.set_logger([](const auto& req, const auto& res) {
your_logger(req, res);
});
Error handler
svr.set_error_handler([](const auto& req, auto& res) {
auto fmt = "<p>Error Status: <span style='color:red;'>%d</span></p>";
char buf[BUFSIZ];
snprintf(buf, sizeof(buf), fmt, res.status);
res.set_content(buf, "text/html");
});
Exception handler
The exception handler gets called if a user routing handler throws an error.
svr.set_exception_handler([](const auto& req, auto& res, std::exception_ptr ep) {
auto fmt = "<h1>Error 500</h1><p>%s</p>";
char buf[BUFSIZ];
try {
std::rethrow_exception(ep);
} catch (std::exception &e) {
snprintf(buf, sizeof(buf), fmt, e.what());
} catch (...) { // See the following NOTE
snprintf(buf, sizeof(buf), fmt, "Unknown Exception");
}
res.set_content(buf, "text/html");
res.status = StatusCode::InternalServerError_500;
});
[!CAUTION] if you don't provide the
catch (...)
block for a rethrown exception pointer, an uncaught exception will end up causing the server crash. Be careful!
Pre routing handler
svr.set_pre_routing_handler([](const auto& req, auto& res) {
if (req.path == "/hello") {
res.set_content("world", "text/html");
return Server::HandlerResponse::Handled;
}
return Server::HandlerResponse::Unhandled;
});
Post routing handler
svr.set_post_routing_handler([](const auto& req, auto& res) {
res.set_header("ADDITIONAL_HEADER", "value");
});
'multipart/form-data' POST data
svr.Post("/multipart", [&](const auto& req, auto& res) {
auto size = req.files.size();
auto ret = req.has_file("name1");
const auto& file = req.get_file_value("name1");
// file.filename;
// file.content_type;
// file.content;
});
Receive content with a content receiver
svr.Post("/content_receiver",
[&](const Request &req, Response &res, const ContentReader &content_reader) {
if (req.is_multipart_form_data()) {
// NOTE: `content_reader` is blocking until every form data field is read
MultipartFormDataItems files;
content_reader(
[&](const MultipartFormData &file) {
files.push_back(file);
return true;
},
[&](const char *data, size_t data_length) {
files.back().content.append(data, data_length);
return true;
});
} else {
std::string body;
content_reader([&](const char *data, size_t data_length) {
body.append(data, data_length);
return true;
});
}
});
Send content with the content provider
const size_t DATA_CHUNK_SIZE = 4;
svr.Get("/stream", [&](const Request &req, Response &res) {
auto data = new std::string("abcdefg");
res.set_content_provider(
data->size(), // Content length
"text/plain", // Content type
[&, data](size_t offset, size_t length, DataSink &sink) {
const auto &d = *data;
sink.write(&d[offset], std::min(length, DATA_CHUNK_SIZE));
return true; // return 'false' if you want to cancel the process.
},
[data](bool success) { delete data; });
});
Without content length:
svr.Get("/stream", [&](const Request &req, Response &res) {
res.set_content_provider(
"text/plain", // Content type
[&](size_t offset, DataSink &sink) {
if (/* there is still data */) {
std::vector<char> data;
// prepare data...
sink.write(data.data(), data.size());
} else {
sink.done(); // No more data
}
return true; // return 'false' if you want to cancel the process.
});
});
Chunked transfer encoding
svr.Get("/chunked", [&](const Request& req, Response& res) {
res.set_chunked_content_provider(
"text/plain",
[](size_t offset, DataSink &sink) {
sink.write("123", 3);
sink.write("345", 3);
sink.write("789", 3);
sink.done(); // No more data
return true; // return 'false' if you want to cancel the process.
}
);
});
With trailer:
svr.Get("/chunked", [&](const Request& req, Response& res) {
res.set_header("Trailer", "Dummy1, Dummy2");
res.set_chunked_content_provider(
"text/plain",
[](size_t offset, DataSink &sink) {
sink.write("123", 3);
sink.write("345", 3);
sink.write("789", 3);
sink.done_with_trailer({
{"Dummy1", "DummyVal1"},
{"Dummy2", "DummyVal2"}
});
return true;
}
);
});
Send file content
svr.Get("/content", [&](const Request &req, Response &res) {
res.set_file_content("./path/to/conent.html");
});
svr.Get("/content", [&](const Request &req, Response &res) {
res.set_file_content("./path/to/conent", "text/html");
});
'Expect: 100-continue' handler
By default, the server sends a 100 Continue
response for an Expect: 100-continue
header.
// Send a '417 Expectation Failed' response.
svr.set_expect_100_continue_handler([](const Request &req, Response &res) {
return StatusCode::ExpectationFailed_417;
});
// Send a final status without reading the message body.
svr.set_expect_100_continue_handler([](const Request &req, Response &res) {
return res.status = StatusCode::Unauthorized_401;
});
Keep-Alive connection
svr.set_keep_alive_max_count(2); // Default is 5
svr.set_keep_alive_timeout(10); // Default is 5
Timeout
svr.set_read_timeout(5, 0); // 5 seconds
svr.set_write_timeout(5, 0); // 5 seconds
svr.set_idle_interval(0, 100000); // 100 milliseconds
Set maximum payload length for reading a request body
svr.set_payload_max_length(1024 * 1024 * 512); // 512MB
[!NOTE] When the request body content type is 'www-form-urlencoded', the actual payload length shouldn't exceed
CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH
.
Server-Sent Events
Please see Server example and Client example.
Default thread pool support
ThreadPool
is used as a default task queue, and the default thread count is 8, or std::thread::hardware_concurrency()
. You can change it with CPPHTTPLIB_THREAD_POOL_COUNT
.
If you want to set the thread count at runtime, there is no convenient way... But here is how.
svr.new_task_queue = [] { return new ThreadPool(12); };
You can also provide an optional parameter to limit the maximum number
of pending requests, i.e. requests accept()
ed by the listener but
still waiting to be serviced by worker threads.
svr.new_task_queue = [] { return new ThreadPool(/*num_threads=*/12, /*max_queued_requests=*/18); };
Default limit is 0 (unlimited). Once the limit is reached, the listener will shutdown the client connection.
Override the default thread pool with yours
You can supply your own thread pool implementation according to your need.
class YourThreadPoolTaskQueue : public TaskQueue {
public:
YourThreadPoolTaskQueue(size_t n) {
pool_.start_with_thread_count(n);
}
virtual bool enqueue(std::function<void()> fn) override {
/* Return true if the task was actually enqueued, or false
* if the caller must drop the corresponding connection. */
return pool_.enqueue(fn);
}
virtual void shutdown() override {
pool_.shutdown_gracefully();
}
private:
YourThreadPool pool_;
};
svr.new_task_queue = [] {
return new YourThreadPoolTaskQueue(12);
};
Client
#include <httplib.h>
#include <iostream>
int main(void)
{
httplib::Client cli("localhost", 1234);
if (auto res = cli.Get("/hi")) {
if (res->status == StatusCode::OK_200) {
std::cout << res->body << std::endl;
}
} else {
auto err = res.error();
std::cout << "HTTP error: " << httplib::to_string(err) << std::endl;
}
}
[!TIP] Constructor with scheme-host-port string is now supported!
httplib::Client cli("localhost");
httplib::Client cli("localhost:8080");
httplib::Client cli("http://localhost");
httplib::Client cli("http://localhost:8080");
httplib::Client cli("https://localhost");
httplib::SSLClient cli("localhost");
Error code
Here is the list of errors from Result::error()
.
enum Error {
Success = 0,
Unknown,
Connection,
BindIPAddress,
Read,
Write,
ExceedRedirectCount,
Canceled,
SSLConnection,
SSLLoadingCerts,
SSLServerVerification,
UnsupportedMultipartBoundaryChars,
Compression,
ConnectionTimeout,
};
GET with HTTP headers
httplib::Headers headers = {
{ "Accept-Encoding", "gzip, deflate" }
};
auto res = cli.Get("/hi", headers);
or
auto res = cli.Get("/hi", {{"Accept-Encoding", "gzip, deflate"}});
or
cli.set_default_headers({
{ "Accept-Encoding", "gzip, deflate" }
});
auto res = cli.Get("/hi");
POST
res = cli.Post("/post", "text", "text/plain");
res = cli.Post("/person", "name=john1¬e=coder", "application/x-www-form-urlencoded");
POST with parameters
httplib::Params params;
params.emplace("name", "john");
params.emplace("note", "coder");
auto res = cli.Post("/post", params);
or
httplib::Params params{
{ "name", "john" },
{ "note", "coder" }
};
auto res = cli.Post("/post", params);
POST with Multipart Form Data
httplib::MultipartFormDataItems items = {
{ "text1", "text default", "", "" },
{ "text2", "aÏb", "", "" },
{ "file1", "h\ne\n\nl\nl\no\n", "hello.txt", "text/plain" },
{ "file2", "{\n \"world\", true\n}\n", "world.json", "application/json" },
{ "file3", "", "", "application/octet-stream" },
};
auto res = cli.Post("/multipart", items);
PUT
res = cli.Put("/resource/foo", "text", "text/plain");
DELETE
res = cli.Delete("/resource/foo");
OPTIONS
res = cli.Options("*");
res = cli.Options("/resource/foo");
Timeout
cli.set_connection_timeout(0, 300000); // 300 milliseconds
cli.set_read_timeout(5, 0); // 5 seconds
cli.set_write_timeout(5, 0); // 5 seconds
Receive content with a content receiver
std::string body;
auto res = cli.Get("/large-data",
[&](const char *data, size_t data_length) {
body.append(data, data_length);
return true;
});
std::string body;
auto res = cli.Get(
"/stream", Headers(),
[&](const Response &response) {
EXPECT_EQ(StatusCode::OK_200, response.status);
return true; // return 'false' if you want to cancel the request.
},
[&](const char *data, size_t data_length) {
body.append(data, data_length);
return true; // return 'false' if you want to cancel the request.
});
Send content with a content provider
std::string body = ...;
auto res = cli.Post(
"/stream", body.size(),
[](size_t offset, size_t length, DataSink &sink) {
sink.write(body.data() + offset, length);
return true; // return 'false' if you want to cancel the request.
},
"text/plain");
Chunked transfer encoding
auto res = cli.Post(
"/stream",
[](size_t offset, DataSink &sink) {
sink.os << "chunked data 1";
sink.os << "chunked data 2";
sink.os << "chunked data 3";
sink.done();
return true; // return 'false' if you want to cancel the request.
},
"text/plain");
With Progress Callback
httplib::Client cli(url, port);
// prints: 0 / 000 bytes => 50% complete
auto res = cli.Get("/", [](uint64_t len, uint64_t total) {
printf("%lld / %lld bytes => %d%% complete\n",
len, total,
(int)(len*100/total));
return true; // return 'false' if you want to cancel the request.
}
);
Authentication
// Basic Authentication
cli.set_basic_auth("user", "pass");
// Digest Authentication
cli.set_digest_auth("user", "pass");
// Bearer Token Authentication
cli.set_bearer_token_auth("token");
[!NOTE] OpenSSL is required for Digest Authentication.
Proxy server support
cli.set_proxy("host", port);
// Basic Authentication
cli.set_proxy_basic_auth("user", "pass");
// Digest Authentication
cli.set_proxy_digest_auth("user", "pass");
// Bearer Token Authentication
cli.set_proxy_bearer_token_auth("pass");
[!NOTE] OpenSSL is required for Digest Authentication.
Range
httplib::Client cli("httpbin.org");
auto res = cli.Get("/range/32", {
httplib::make_range_header({{1, 10}}) // 'Range: bytes=1-10'
});
// res->status should be 206.
// res->body should be "bcdefghijk".
httplib::make_range_header({{1, 10}, {20, -1}}) // 'Range: bytes=1-10, 20-'
httplib::make_range_header({{100, 199}, {500, 599}}) // 'Range: bytes=100-199, 500-599'
httplib::make_range_header({{0, 0}, {-1, 1}}) // 'Range: bytes=0-0, -1'
Keep-Alive connection
httplib::Client cli("localhost", 1234);
cli.Get("/hello"); // with "Connection: close"
cli.set_keep_alive(true);
cli.Get("/world");
cli.set_keep_alive(false);
cli.Get("/last-request"); // with "Connection: close"
Redirect
httplib::Client cli("yahoo.com");
auto res = cli.Get("/");
res->status; // 301
cli.set_follow_location(true);
res = cli.Get("/");
res->status; // 200
Use a specific network interface
[!NOTE] This feature is not available on Windows, yet.
cli.set_interface("eth0"); // Interface name, IP address or host name
Compression
The server can apply compression to the following MIME type contents:
- all text types except text/event-stream
- image/svg+xml
- application/javascript
- application/json
- application/xml
- application/xhtml+xml
Zlib Support
'gzip' compression is available with CPPHTTPLIB_ZLIB_SUPPORT
. libz
should be linked.
Brotli Support
Brotli compression is available with CPPHTTPLIB_BROTLI_SUPPORT
. Necessary libraries should be linked.
Please see https://github.com/google/brotli for more detail.
Compress request body on client
cli.set_compress(true);
res = cli.Post("/resource/foo", "...", "text/plain");
Compress response body on client
cli.set_decompress(false);
res = cli.Get("/resource/foo", {{"Accept-Encoding", "gzip, deflate, br"}});
res->body; // Compressed data
Use poll
instead of select
select
system call is used as default since it's more widely supported. If you want to let cpp-httplib use poll
instead, you can do so with CPPHTTPLIB_USE_POLL
.
Split httplib.h into .h and .cc
$ ./split.py -h
usage: split.py [-h] [-e EXTENSION] [-o OUT]
This script splits httplib.h into .h and .cc parts.
optional arguments:
-h, --help show this help message and exit
-e EXTENSION, --extension EXTENSION
extension of the implementation file (default: cc)
-o OUT, --out OUT where to write the files (default: out)
$ ./split.py
Wrote out/httplib.h and out/httplib.cc
Dockerfile for Static HTTP Server
Dockerfile for static HTTP server is available. Port number of this HTTP server is 80, and it serves static files from /html
directory in the container.
> docker build -t cpp-httplib-server .
...
> docker run --rm -it -p 8080:80 -v ./docker/html:/html cpp-httplib-server
Serving HTTP on 0.0.0.0 port 80 ...
192.168.65.1 - - [31/Aug/2024:21:33:56 +0000] "GET / HTTP/1.1" 200 599 "-" "curl/8.7.1"
192.168.65.1 - - [31/Aug/2024:21:34:26 +0000] "GET / HTTP/1.1" 200 599 "-" "Mozilla/5.0 ..."
192.168.65.1 - - [31/Aug/2024:21:34:26 +0000] "GET /favicon.ico HTTP/1.1" 404 152 "-" "Mozilla/5.0 ..."
From Docker Hub
> docker run --rm -it -p 8080:80 -v ./docker/html:/html yhirose4dockerhub/cpp-httplib-server
...
> docker run --init --rm -it -p 8080:80 -v ./docker/html:/html cpp-httplib-server
Serving HTTP on 0.0.0.0 port 80 ...
192.168.65.1 - - [31/Aug/2024:21:33:56 +0000] "GET / HTTP/1.1" 200 599 "-" "curl/8.7.1"
192.168.65.1 - - [31/Aug/2024:21:34:26 +0000] "GET / HTTP/1.1" 200 599 "-" "Mozilla/5.0 ..."
192.168.65.1 - - [31/Aug/2024:21:34:26 +0000] "GET /favicon.ico HTTP/1.1" 404 152 "-" "Mozilla/5.0 ..."
NOTE
g++
g++ 4.8 and below cannot build this library since <regex>
in the versions are broken.
Windows
Include httplib.h
before Windows.h
or include Windows.h
by defining WIN32_LEAN_AND_MEAN
beforehand.
#include <httplib.h>
#include <Windows.h>
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <httplib.h>
[!NOTE] cpp-httplib officially supports only the latest Visual Studio. It might work with former versions of Visual Studio, but I can no longer verify it. Pull requests are always welcome for the older versions of Visual Studio unless they break the C++11 conformance.
[!NOTE] Windows 8 or lower, Visual Studio 2013 or lower, and Cygwin and MSYS2 including MinGW are neither supported nor tested.
License
MIT license (© 2024 Yuji Hirose)
Special Thanks To
These folks made great contributions to polish this library to totally another level from a simple toy!
Top Related Projects
The C++ REST SDK is a Microsoft project for cloud-based client-server communication in native code using a modern asynchronous C++ API design. This project aims to help C++ developers connect to and interact with services.
Simple, secure & standards compliant web server for the most demanding of applications
A curated list of awesome C++ (or C) frameworks, libraries, resources, and shiny things. Inspired by awesome-... stuff.
HTTP and WebSocket built on Boost.Asio in C++11
C++ Requests: Curl for People, a spiritual port of Python Requests.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot