mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-04-11 19:28:30 +00:00
WebSocket and Dynamic Thread Pool support (#2368)
* WebSocket support * Validate selected subprotocol in WebSocket handshake * Fix problem with a Unit test * Dynamic Thread Pool support * Fix race condition in new Dynamic ThreadPool
This commit is contained in:
@@ -18,7 +18,7 @@ ZLIB_SUPPORT = -DCPPHTTPLIB_ZLIB_SUPPORT -lz
|
||||
BROTLI_DIR = $(PREFIX)/opt/brotli
|
||||
BROTLI_SUPPORT = -DCPPHTTPLIB_BROTLI_SUPPORT -I$(BROTLI_DIR)/include -L$(BROTLI_DIR)/lib -lbrotlicommon -lbrotlienc -lbrotlidec
|
||||
|
||||
all: server client hello simplecli simplesvr upload redirect ssesvr ssecli benchmark one_time_request server_and_client accept_header
|
||||
all: server client hello simplecli simplesvr upload redirect ssesvr ssecli wsecho benchmark one_time_request server_and_client accept_header
|
||||
|
||||
server : server.cc ../httplib.h Makefile
|
||||
$(CXX) -o server $(CXXFLAGS) server.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT)
|
||||
@@ -47,6 +47,9 @@ ssesvr : ssesvr.cc ../httplib.h Makefile
|
||||
ssecli : ssecli.cc ../httplib.h Makefile
|
||||
$(CXX) -o ssecli $(CXXFLAGS) ssecli.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT)
|
||||
|
||||
wsecho : wsecho.cc ../httplib.h Makefile
|
||||
$(CXX) -o wsecho $(CXXFLAGS) wsecho.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT)
|
||||
|
||||
benchmark : benchmark.cc ../httplib.h Makefile
|
||||
$(CXX) -o benchmark $(CXXFLAGS) benchmark.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT)
|
||||
|
||||
@@ -64,4 +67,4 @@ pem:
|
||||
openssl req -new -key key.pem | openssl x509 -days 3650 -req -signkey key.pem > cert.pem
|
||||
|
||||
clean:
|
||||
rm server client hello simplecli simplesvr upload redirect ssesvr ssecli benchmark one_time_request server_and_client accept_header *.pem
|
||||
rm server client hello simplecli simplesvr upload redirect ssesvr ssecli wsecho benchmark one_time_request server_and_client accept_header *.pem
|
||||
|
||||
135
example/wsecho.cc
Normal file
135
example/wsecho.cc
Normal file
@@ -0,0 +1,135 @@
|
||||
#include <httplib.h>
|
||||
#include <iostream>
|
||||
|
||||
using namespace httplib;
|
||||
|
||||
const auto html = R"HTML(
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>WebSocket Demo</title>
|
||||
<style>
|
||||
body { font-family: monospace; margin: 2em; }
|
||||
#log { height: 300px; overflow-y: scroll; border: 1px solid #ccc; padding: 8px; }
|
||||
.controls { margin: 8px 0; }
|
||||
button { margin-right: 4px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>WebSocket Demo</h1>
|
||||
<p>Server accepts subprotocols: <b>echo</b>, <b>chat</b> (or none)</p>
|
||||
|
||||
<div class="controls">
|
||||
<label>Subprotocols: </label>
|
||||
<input id="protos" type="text" value="echo, chat" placeholder="leave empty for none" />
|
||||
<button onclick="doConnect()">Connect</button>
|
||||
<button onclick="doDisconnect()">Disconnect</button>
|
||||
</div>
|
||||
|
||||
<div class="controls">
|
||||
<input id="msg" type="text" placeholder="Type a message..." />
|
||||
<button onclick="doSend()">Send</button>
|
||||
</div>
|
||||
|
||||
<div class="controls">
|
||||
<button onclick="startAuto()">Start Auto (1s)</button>
|
||||
<button onclick="stopAuto()">Stop Auto</button>
|
||||
<span id="auto-status"></span>
|
||||
</div>
|
||||
|
||||
<pre id="log"></pre>
|
||||
|
||||
<script>
|
||||
var sock = null;
|
||||
var logEl = document.getElementById("log");
|
||||
var statusEl = document.getElementById("auto-status");
|
||||
var timer = null;
|
||||
var seq = 0;
|
||||
|
||||
function appendLog(text) {
|
||||
logEl.textContent += text + "\n";
|
||||
logEl.scrollTop = logEl.scrollHeight;
|
||||
}
|
||||
|
||||
function doConnect() {
|
||||
if (sock && sock.readyState <= 1) { sock.close(); }
|
||||
var input = document.getElementById("protos").value.trim();
|
||||
var protocols = input ? input.split(/\s*,\s*/).filter(Boolean) : [];
|
||||
sock = new WebSocket("ws://" + location.host + "/ws", protocols);
|
||||
appendLog("[connecting] proposed: " + (protocols.length ? protocols.join(", ") : "(none)"));
|
||||
sock.onopen = function() { appendLog("[connected] subprotocol: " + (sock.protocol || "(none)")); };
|
||||
sock.onclose = function() { appendLog("[disconnected]"); stopAuto(); };
|
||||
sock.onmessage = function(e) { appendLog("< " + e.data); };
|
||||
}
|
||||
|
||||
function doDisconnect() {
|
||||
if (sock) { sock.close(); }
|
||||
}
|
||||
|
||||
function doSend() {
|
||||
var input = document.getElementById("msg");
|
||||
if (!sock || sock.readyState !== 1 || input.value === "") return;
|
||||
sock.send(input.value);
|
||||
appendLog("> " + input.value);
|
||||
input.value = "";
|
||||
}
|
||||
|
||||
function startAuto() {
|
||||
if (timer || !sock || sock.readyState !== 1) return;
|
||||
seq = 0;
|
||||
statusEl.textContent = "running...";
|
||||
timer = setInterval(function() {
|
||||
if (!sock || sock.readyState !== 1) { stopAuto(); return; }
|
||||
var msg = "auto #" + seq++;
|
||||
sock.send(msg);
|
||||
appendLog("> " + msg);
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function stopAuto() {
|
||||
if (timer) { clearInterval(timer); timer = null; }
|
||||
statusEl.textContent = "";
|
||||
}
|
||||
|
||||
document.getElementById("msg").addEventListener("keydown", function(e) {
|
||||
if (e.key === "Enter") doSend();
|
||||
});
|
||||
|
||||
doConnect();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
)HTML";
|
||||
|
||||
int main(void) {
|
||||
Server svr;
|
||||
|
||||
svr.Get("/", [&](const Request & /*req*/, Response &res) {
|
||||
res.set_content(html, "text/html");
|
||||
});
|
||||
|
||||
svr.WebSocket(
|
||||
"/ws",
|
||||
[](const Request &req, ws::WebSocket &ws) {
|
||||
std::cout << "WebSocket connected from " << req.remote_addr
|
||||
<< std::endl;
|
||||
|
||||
std::string msg;
|
||||
while (ws.read(msg)) {
|
||||
std::cout << "Received: " << msg << std::endl;
|
||||
ws.send("echo: " + msg);
|
||||
}
|
||||
|
||||
std::cout << "WebSocket disconnected" << std::endl;
|
||||
},
|
||||
[](const std::vector<std::string> &protocols) -> std::string {
|
||||
for (const auto &p : protocols) {
|
||||
if (p == "echo" || p == "chat") { return p; }
|
||||
}
|
||||
return "";
|
||||
});
|
||||
|
||||
std::cout << "Listening on http://localhost:8080" << std::endl;
|
||||
svr.listen("localhost", 8080);
|
||||
}
|
||||
Reference in New Issue
Block a user