diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index cc0922e..851c290 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -10,6 +10,7 @@ set(EXAMPLES
client
task
cppcon-2024
+ milano
)
foreach(EXAMPLE ${EXAMPLES})
diff --git a/examples/data/index-milano.html b/examples/data/index-milano.html
new file mode 100644
index 0000000..aea54f3
--- /dev/null
+++ b/examples/data/index-milano.html
@@ -0,0 +1,10 @@
+
+
+ Ciao Milano!
+
+
+
+ Ciao Milano!
+
+
+
diff --git a/examples/data/itcpp.png b/examples/data/itcpp.png
new file mode 100644
index 0000000..12c1056
Binary files /dev/null and b/examples/data/itcpp.png differ
diff --git a/examples/milano.cpp b/examples/milano.cpp
new file mode 100644
index 0000000..6800480
--- /dev/null
+++ b/examples/milano.cpp
@@ -0,0 +1,97 @@
+// examples/http-server.cpp -*-C++-*-
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#include
+#include
+#include "demo_algorithm.hpp"
+#include "demo_error.hpp"
+#include "demo_scope.hpp"
+#include "demo_task.hpp"
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace ex = beman::execution26;
+namespace net = beman::net29;
+using namespace std::chrono_literals;
+
+// ----------------------------------------------------------------------------
+
+std::unordered_map files{
+ {"/", "examples/data/index-milano.html"},
+ {"/favicon.ico", "examples/data/favicon.ico"},
+ {"/logo.png", "examples/data/logo.png"},
+ {"/itcpp.png", "examples/data/itcpp.png"},
+};
+
+auto timeout(auto scheduler, auto dur, ex::sender auto sender) {
+ return demo::when_any(
+ net::resume_after(scheduler, dur)
+ | demo::into_error([]{ return std::error_code(); }),
+ std::move(sender)
+ );
+}
+
+using on_exit = std::unique_ptr;
+demo::task<> run_client(auto client, auto s) {
+ on_exit exit("client exiting");
+ char buffer[8194];
+ std::ostringstream out;
+ try {
+ while (true) {
+ auto n = co_await timeout(s, 1s, net::async_receive(client, net::buffer(buffer)));
+ if (n == 0u)
+ co_return;
+ // std::cout << "received=" << std::string_view(buffer, n) << "\n";
+ std::istringstream in(std::string(buffer, n));
+ std::string method, url, version;
+ if (!(in >> method >> url >> version))
+ co_return;
+ auto it = files.find(url);
+ std::cout << "url=" << url << " found=" << (it == files.end()? "no": "yes") << "\n";
+ std::string content;
+ if (it != files.end()) {
+ std::ifstream fin(it->second);
+ out.str({});
+ out << fin.rdbuf();
+ content = out.str();
+ }
+ out.str(std::string());
+ out << "HTTP/1.1 200 found\r\n"
+ << "Content-Length: " << content.size() << "\r\n"
+ << "\r\n"
+ << content;
+
+ content = out.str();
+ co_await net::async_send(client, net::buffer(content));
+ //break;
+ }
+ } catch (std::exception const& ex) {
+ std::cout << "received timeout! ex=" << ex.what() << "\n";
+ } catch (...) {
+ std::cout << "received timeout!\n";
+ }
+}
+
+auto main() -> int
+{
+ demo::scope scope;
+ net::io_context context;
+
+ scope.spawn([](auto& context, auto& scope)->demo::task<> {
+ net::ip::tcp::endpoint ep(net::ip::address_v4::any(), 12345);
+ net::ip::tcp::acceptor acceptor(context, ep);
+ while (true) {
+ auto[client, address] = co_await net::async_accept(acceptor);
+ std::cout << "received a connection from " << address << "\n";
+ scope.spawn(run_client(std::move(client), context.get_scheduler()));
+ }
+ }(context, scope));
+
+ context.run();
+
+
+}