mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-28 12:40:54 +00:00
Through a CONNECT proxy it is the proxy that connects to the origin, and the CONNECT target was always the original hostname, so there was no way to send the tunnel to another address. set_tunnel_hostname_addr_map() sets that target on SSLClient, Client and WebSocketClient. The CONNECT request's Host follows it, including the Digest retry, while the Host header, the SNI and the certificate check inside the tunnel keep the original hostname. The map is also copied to a redirect client. set_hostname_addr_map() is deprecated in favor of set_direct_hostname_addr_map(), which behaves the same and names the connection it applies to. The two maps are independent and correspond to curl's --resolve and --connect-to; neither applies to the proxy's own address.
231 lines
6.8 KiB
Markdown
231 lines
6.8 KiB
Markdown
---
|
|
title: "What's Next"
|
|
order: 9
|
|
---
|
|
|
|
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.
|
|
|
|
```cpp
|
|
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());
|
|
}
|
|
}
|
|
```
|
|
|
|
Note that `stream::Get()` reads no more of the body than the client's `set_payload_max_length()` allows, which is 100MB by default. For larger downloads, raise it, or set it to 0 for no limit.
|
|
|
|
You can also pass a `content_receiver` callback to `Get()`. This approach works with Keep-Alive, and it has no size limit unless you set one with `set_payload_max_length()`.
|
|
|
|
```cpp
|
|
httplib::Client cli("http://localhost:8080");
|
|
|
|
cli.Get("/stream", [](const char *data, size_t len) {
|
|
std::cout.write(data, len);
|
|
return true;
|
|
});
|
|
```
|
|
|
|
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.
|
|
|
|
```cpp
|
|
// 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; // Call sink.done() to finish
|
|
});
|
|
});
|
|
```
|
|
|
|
For uploading large files, `make_file_provider()` comes in handy. It streams the file instead of loading it all into memory.
|
|
|
|
```cpp
|
|
httplib::Client cli("http://localhost:8080");
|
|
|
|
auto res = cli.Post("/upload", {}, {}, {
|
|
httplib::make_file_provider("file", "/path/to/large-file.zip")
|
|
});
|
|
```
|
|
|
|
## Server-Sent Events (SSE)
|
|
|
|
We provide an SSE client as well. It supports automatic reconnection and resuming via `Last-Event-ID`.
|
|
|
|
```cpp
|
|
httplib::Client cli("http://localhost:8080");
|
|
httplib::sse::SSEClient sse(cli, "/events");
|
|
|
|
sse.on_message([](const httplib::sse::SSEMessage &msg) {
|
|
std::cout << msg.event << ": " << msg.data << std::endl;
|
|
});
|
|
|
|
sse.start(); // Blocking, with auto-reconnection
|
|
```
|
|
|
|
You can also set separate handlers for each event type.
|
|
|
|
```cpp
|
|
sse.on_event("update", [](const httplib::sse::SSEMessage &msg) {
|
|
// Only handles "update" events
|
|
});
|
|
```
|
|
|
|
## Authentication
|
|
|
|
The client has helpers for Basic auth, Bearer Token auth, and Digest auth.
|
|
|
|
```cpp
|
|
httplib::Client cli("https://api.example.com");
|
|
cli.set_basic_auth("user", "password");
|
|
cli.set_bearer_token_auth("my-token");
|
|
```
|
|
|
|
## Compression
|
|
|
|
We support compression and decompression with gzip, Brotli, and Zstandard. Define the corresponding macro when you compile.
|
|
|
|
| Method | Macro |
|
|
| -- | -- |
|
|
| gzip | `CPPHTTPLIB_ZLIB_SUPPORT` |
|
|
| Brotli | `CPPHTTPLIB_BROTLI_SUPPORT` |
|
|
| Zstandard | `CPPHTTPLIB_ZSTD_SUPPORT` |
|
|
|
|
```cpp
|
|
httplib::Client cli("https://example.com");
|
|
cli.set_compress(true); // Compress request body
|
|
cli.set_decompress(true); // Decompress response body
|
|
```
|
|
|
|
## Proxy
|
|
|
|
You can connect through an HTTP proxy.
|
|
|
|
```cpp
|
|
httplib::Client cli("https://example.com");
|
|
cli.set_proxy("proxy.example.com", 8080);
|
|
cli.set_proxy_basic_auth("user", "password");
|
|
```
|
|
|
|
## Timeouts
|
|
|
|
You can set connection, read, and write timeouts individually.
|
|
|
|
```cpp
|
|
httplib::Client cli("https://example.com");
|
|
cli.set_connection_timeout(5, 0); // 5 seconds
|
|
cli.set_read_timeout(10, 0); // 10 seconds
|
|
cli.set_write_timeout(10, 0); // 10 seconds
|
|
```
|
|
|
|
## Keep-Alive
|
|
|
|
If you're making multiple requests to the same server, enable Keep-Alive. It reuses the TCP connection, which is much more efficient.
|
|
|
|
```cpp
|
|
httplib::Client cli("https://example.com");
|
|
cli.set_keep_alive(true);
|
|
```
|
|
|
|
## Server Middleware
|
|
|
|
You can hook into request processing before and after handlers run.
|
|
|
|
```cpp
|
|
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 just before the response is sent
|
|
res.set_header("X-Server", "cpp-httplib");
|
|
});
|
|
```
|
|
|
|
Use `res.user_data` to pass data from middleware to handlers. This is useful for sharing things like decoded auth tokens.
|
|
|
|
```cpp
|
|
svr.set_pre_routing_handler([](const auto &req, auto &res) {
|
|
res.user_data.set("auth_user", std::string("alice"));
|
|
return httplib::Server::HandlerResponse::Unhandled;
|
|
});
|
|
|
|
svr.Get("/me", [](const httplib::Request &req, httplib::Response &res) {
|
|
auto *user = res.user_data.get<std::string>("auth_user");
|
|
res.set_content("Hello, " + *user, "text/plain");
|
|
});
|
|
```
|
|
|
|
You can also customize error and exception handlers.
|
|
|
|
```cpp
|
|
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.
|
|
|
|
```cpp
|
|
svr.set_logger([](const auto &req, const auto &res) {
|
|
std::cout << req.method << " " << req.path << " " << res.status << std::endl;
|
|
});
|
|
```
|
|
|
|
## Unix Domain Socket
|
|
|
|
In addition to TCP, we support Unix Domain Sockets. You can use them for inter-process communication on the same machine.
|
|
|
|
```cpp
|
|
// Server
|
|
httplib::Server svr;
|
|
svr.set_address_family(AF_UNIX);
|
|
svr.listen("/tmp/httplib.sock", 80); // The port is unused, but must not be 0
|
|
```
|
|
|
|
```cpp
|
|
// Client
|
|
httplib::Client cli("http://localhost");
|
|
cli.set_address_family(AF_UNIX);
|
|
cli.set_direct_hostname_addr_map({{"localhost", "/tmp/httplib.sock"}});
|
|
|
|
auto res = cli.Get("/");
|
|
```
|
|
|
|
## Learn More
|
|
|
|
Want to dig deeper? Check out these resources.
|
|
|
|
- Cookbook — A collection of recipes for common use cases
|
|
- [README](https://github.com/yhirose/cpp-httplib/blob/master/README.md) — Full API reference
|
|
- [README-sse](https://github.com/yhirose/cpp-httplib/blob/master/README-sse.md) — How to use Server-Sent Events
|
|
- [README-stream](https://github.com/yhirose/cpp-httplib/blob/master/README-stream.md) — How to use the Streaming API
|
|
- [README-websocket](https://github.com/yhirose/cpp-httplib/blob/master/README-websocket.md) — How to use the WebSocket server
|