@@ -14,12 +14,12 @@ The C++20 streaming API allows you to process HTTP response bodies chunk by chun
1414## Requirements
1515
1616- C++20 compiler with coroutine support
17- - Include ` httplib20 .h` (which includes ` httplib.h ` )
17+ - Include ` httplib-stream .h` (which includes ` httplib.h ` )
1818
1919## Quick Start
2020
2121``` cpp
22- #include " httplib20 .h"
22+ #include " httplib-stream .h"
2323
2424int main () {
2525 httplib::Client cli("http://localhost:8080");
@@ -82,10 +82,10 @@ if (handle.is_valid()) {
8282
8383### High-Level API: `GetStream()` and `StreamingResult`
8484
85- The `httplib20 .h` header provides a more ergonomic API using C++20 coroutines.
85+ The `httplib-stream .h` header provides a more ergonomic API using C++20 coroutines.
8686
8787```cpp
88- #include "httplib20 .h"
88+ #include "httplib-stream .h"
8989
9090httplib::Client cli("http://localhost:8080");
9191
@@ -124,68 +124,55 @@ for (auto chunk : result.body(1024)) {
124124### Example 1: SSE (Server-Sent Events) Client
125125
126126``` cpp
127- #include " httplib20 .h"
127+ #include " httplib-stream .h"
128128#include < iostream>
129129
130130int main () {
131- httplib::Client cli("http://localhost:8080");
131+ httplib::Client cli("http://localhost:1234");
132+
132133 auto result = httplib::GetStream(cli, "/events");
134+ if (!result) { return 1; }
133135
134- if (!result) {
135- std::cerr << "Connection failed\n";
136- return 1;
137- }
138-
139- std::cout << "Connected, receiving events...\n";
140-
141- std::string buffer;
142- for (auto chunk : result.body(256)) {
143- buffer += chunk;
144-
145- // Process complete SSE messages
146- size_t pos;
147- while ((pos = buffer.find("\n\n")) != std::string::npos) {
148- std::string message = buffer.substr(0, pos);
149- buffer.erase(0, pos + 2);
150-
151- std::cout << "Event: " << message << "\n";
152- }
136+ for (auto chunk : result.body()) {
137+ std::cout << chunk << std::flush;
153138 }
154139
155140 return 0;
156141}
157142```
158143
159- ### Example 2: LLM Streaming Response (Ollama-style)
144+ For a complete SSE client with auto-reconnection and event parsing, see ` example/ssecli-stream.cc ` .
145+
146+ ### Example 2: LLM Streaming Response
160147
161148``` cpp
162- #include " httplib20 .h"
149+ #include " httplib-stream .h"
163150#include < iostream>
164151
165152int main () {
166- httplib::Client cli("http://localhost:11434");
167-
168- // Note: For POST requests, use open_stream with custom request
169- // This example shows the pattern for streaming responses
153+ httplib::Client cli("http://localhost:11434"); // Ollama
170154
171- httplib::Headers headers = {{"Content-Type", "application/json"}};
172- auto result = httplib::GetStream(cli, "/api/generate", headers);
155+ auto result = httplib::GetStream(cli, "/api/generate");
173156
174157 if (result && result.status() == 200) {
175- for (auto chunk : result.body(1024)) {
176- // Each chunk may contain JSON like: {"response": "Hello"}
158+ for (auto chunk : result.body()) {
177159 std::cout << chunk << std::flush;
178160 }
179161 }
180162
163+ // Check for connection errors
164+ if (result.read_error() != httplib::Error::Success) {
165+ std::cerr << "Connection lost\n";
166+ }
167+
181168 return 0;
182169}
183170```
184171
185172### Example 3: Large File Download with Progress
186173
187174``` cpp
188- #include " httplib20 .h"
175+ #include " httplib-stream .h"
189176#include < fstream>
190177#include < iostream>
191178
@@ -215,44 +202,36 @@ int main() {
215202### Example 4: Reverse Proxy Streaming
216203
217204``` cpp
218- #include " httplib20 .h"
205+ #include " httplib .h"
219206
220- int main () {
221- httplib::Server svr;
207+ httplib::Server svr;
208+
209+ svr.Get(" /proxy/(.*)" , [](const httplib::Request& req, httplib::Response& res) {
210+ httplib::Client upstream("http://backend:8080");
211+ auto handle = upstream.open_stream("/" + req.matches[1].str());
222212
223- svr.Get("/proxy/(.*)", [](const httplib::Request& req, httplib::Response& res) {
224- httplib::Client upstream("http://backend:8080");
225- auto handle = upstream.open_stream("/" + req.matches[1].str());
226-
227- if (!handle.is_valid()) {
228- res.status = 502;
229- return;
230- }
231-
232- // Forward status and headers
233- res.status = handle.response->status;
234- for (const auto& h : handle.response->headers) {
235- res.set_header(h.first, h.second);
236- }
237-
238- // Stream body using chunked transfer
239- res.set_chunked_content_provider(
240- handle.response->get_header_value("Content-Type"),
241- [handle = std::move(handle)](size_t, httplib::DataSink& sink) mutable {
242- char buf[8192];
243- ssize_t n = handle.read(buf, sizeof(buf));
244- if (n > 0) {
245- sink.write(buf, static_cast<size_t>(n));
246- return true;
247- }
248- sink.done();
213+ if (!handle.is_valid()) {
214+ res.status = 502;
215+ return;
216+ }
217+
218+ res.status = handle.response->status;
219+ res.set_chunked_content_provider(
220+ handle.response->get_header_value("Content-Type"),
221+ [handle = std::move(handle)](size_t, httplib::DataSink& sink) mutable {
222+ char buf[8192];
223+ auto n = handle.read(buf, sizeof(buf));
224+ if (n > 0) {
225+ sink.write(buf, static_cast<size_t>(n));
249226 return true;
250227 }
251- );
252- });
253-
254- svr.listen("0.0.0.0", 3000);
255- }
228+ sink.done();
229+ return true;
230+ }
231+ );
232+ });
233+
234+ svr.listen(" 0.0.0.0" , 3000 );
256235```
257236
258237## Comparison with Existing APIs
@@ -310,4 +289,5 @@ clang++ -std=c++20 -o myapp myapp.cpp -lpthread -lssl -lcrypto
310289
311290- [ Issue #2269 ] ( https://github.com/yhirose/cpp-httplib/issues/2269 ) - Original feature request
312291- [ httplib.h] ( ./httplib.h ) - Main library
313- - [ httplib20.h] ( ./httplib20.h ) - C++20 extensions
292+ - [ httplib-stream.h] ( ./httplib-stream.h ) - C++20 extensions
293+ - [ example/ssecli-stream.cc] ( ./example/ssecli-stream.cc ) - SSE client with auto-reconnection
0 commit comments