mirror of
https://github.com/yhirose/cpp-httplib
synced 2024-11-21 14:29:10 -07:00
No description
7e92ffec48
While trying to implement streaming of internet radio, where a ContentReceiver is needed to handle the audio data, I had the problem, that important information about the stream data is part of the HTTP header (e.g. size of audio chunks between meta data), so I added a ResponseHandler and a new Get variant, to gain access to the header before handling the first chunk of data. The ResponseHandler can abort the request by returning false, in the same way as the ContentReceiver. A test case was also added. |
||
---|---|---|
example | ||
test | ||
.gitignore | ||
.travis.yml | ||
appveyor.yml | ||
CMakeLists.txt | ||
httplib.h | ||
LICENSE | ||
README.md |
cpp-httplib
A C++ single-file header-only cross platform HTTP/HTTPS library.
It's extremely easy to setup. Just include httplib.h file in your code!
Server Example
#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");
});
svr.Get(R"(/numbers/(\d+))", [&](const Request& req, Response& res) {
auto numbers = req.matches[1];
res.set_content(numbers, "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
svr.set_base_dir("./www");
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) {
const char* 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");
});
'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;
auto body = req.body.substr(file.offset, file.length));
})
Stream content with Content provider
const uint64_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
[data](uint64_t offset, uint64_t length, Out out) {
const auto &d = *data;
out(&d[offset], std::min(length, DATA_CHUNK_SIZE));
},
[data] { delete data; });
});
Chunked transfer encoding
svr.Get("/chunked", [&](const Request& req, Response& res) {
res.set_chunked_content_provider(
[](uint64_t offset, Out out, Done done) {
out("123", 3);
out("345", 3);
out("789", 3);
done();
}
);
});
Default thread pool supporet
Set thread count to 8:
#define CPPHTTPLIB_THREAD_POOL_COUNT 8
Disable the default thread pool:
#define CPPHTTPLIB_THREAD_POOL_COUNT 0
Override the default thread pool with yours
class YourThreadPoolTaskQueue : public TaskQueue {
public:
YourThreadPoolTaskQueue(size_t n) {
pool_.start_with_thread_count(n);
}
virtual void enqueue(std::function<void()> fn) override {
pool_.enqueue(fn);
}
virtual void shutdown() override {
pool_.shutdown_gracefully();
}
private:
YourThreadPool pool_;
};
svr.new_task_queue = [] {
return new YourThreadPoolTaskQueue(12);
};
Client Example
GET
#include <httplib.h>
#include <iostream>
int main(void)
{
httplib::Client cli("localhost", 1234);
auto res = cli.Get("/hi");
if (res && res->status == 200) {
std::cout << res->body << std::endl;
}
}
GET with HTTP headers
httplib::Headers headers = {
{ "Accept-Encoding", "gzip, deflate" }
};
auto res = cli.Get("/hi", headers);
GET with Content Receiver
std::string body;
auto res = cli.Get("/large-data",
[&](const char *data, uint64_t data_length, uint64_t offset, uint64_t content_length) {
body.append(data, data_length);
});
assert(res->body.empty());
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");
Connection Timeout
httplib::Client cli("localhost", 8080, 5); // timeouts in 5 seconds
With Progress Callback
httplib::Client client(url, port);
// prints: 0 / 000 bytes => 50% complete
std::shared_ptr<httplib::Response> res =
cli.Get("/", [](uint64_t len, uint64_t total) {
printf("%lld / %lld bytes => %d%% complete\n",
len, total,
(int)((len/total)*100));
return true; // return 'false' if you want to cancel the request.
}
);
This feature was contributed by underscorediscovery.
Basic Authentication
httplib::Client cli("httplib.org");
auto res = cli.Get("/basic-auth/hello/world", {
httplib::make_basic_authentication_header("hello", "world")
});
// res->status should be 200
// res->body should be "{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n".
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
cli.set_keep_alive_max_count(2); // Default is 5
std::vector<Request> requests;
Get(requests, "/get-request1");
Get(requests, "/get-request2");
Post(requests, "/post-request1", "text", "text/plain");
Post(requests, "/post-request2", "text", "text/plain");
std::vector<Response> responses;
if (cli.send(requests, responses)) {
for (const auto& res: responses) {
...
}
}
Redirect
httplib::Client cli("yahoo.com");
auto res = cli.Get("/");
res->status; // 301
cli.follow_location(true);
res = cli.Get("/");
res->status; // 200
OpenSSL Support
SSL support is available with CPPHTTPLIB_OPENSSL_SUPPORT
. libssl
and libcrypto
should be linked.
#define CPPHTTPLIB_OPENSSL_SUPPORT
SSLServer svr("./cert.pem", "./key.pem");
SSLClient cli("localhost", 8080);
cli.set_ca_cert_path("./ca-bundle.crt");
cli.enable_server_certificate_verification(true);
Zlib Support
'gzip' compression is available with CPPHTTPLIB_ZLIB_SUPPORT
.
The server applies gzip compression to the following MIME type contents:
- all text types
- image/svg+xml
- application/javascript
- application/json
- application/xml
- application/xhtml+xml
NOTE
g++ 4.8 cannot build this library since <regex>
in g++4.8 is broken.
License
MIT license (© 2019 Yuji Hirose)