-
-
Couldn't load subscription status.
- Fork 503
Description
Feature Request: WebSocket Upgrade Extension Point / Hook
Summary
Add an extension point that allows custom logic to be executed during WebSocket upgrade requests, similar to how middleware works for regular HTTP requests.
Motivation
Currently, WebSocket upgrade requests bypass the normal request handling pipeline and go directly to handle_upgrade(). This means:
- Middleware is not invoked for WebSocket upgrade requests
- No way to intercept or modify WebSocket upgrade behavior without patching Crow
- Cannot implement custom logic like redirects, authentication, or protocol validation at the upgrade stage
Use Case Examples
1. HTTP to HTTPS WebSocket Redirect
Automatically redirect ws:// connections to wss:// for security:
// Desired usage
app.websocket_upgrade_hook([](const request& req, response& res, bool is_ssl) {
if (!is_ssl && should_redirect_to_https()) {
res.code = 308;
res.set_header("Location", "wss://" + get_https_url(req));
return false; // Don't proceed with upgrade
}
return true; // Proceed with upgrade
});2. Authentication/Authorization
Validate tokens or permissions before allowing WebSocket upgrade:
app.websocket_upgrade_hook([](const request& req, response& res, bool is_ssl) {
if (!is_authenticated(req)) {
res.code = 401;
res.set_header("WWW-Authenticate", "Bearer");
return false;
}
return true;
});3. Rate Limiting
Apply rate limits specifically to WebSocket connections:
app.websocket_upgrade_hook([](const request& req, response& res, bool is_ssl) {
if (rate_limiter.is_exceeded(req.remote_ip_address)) {
res.code = 429;
return false;
}
return true;
});4. Protocol Validation
Enforce specific WebSocket subprotocols or extensions:
app.websocket_upgrade_hook([](const request& req, response& res, bool is_ssl) {
auto protocol = req.get_header_value("Sec-WebSocket-Protocol");
if (!is_supported_protocol(protocol)) {
res.code = 400;
return false;
}
return true;
});Proposed Implementation
Option 1: Hook/Callback Function
Add a simple hook that's called before WebSocket upgrade:
template<typename Adaptor, typename Handler, typename... Middlewares>
class Connection {
// ...
void handle() {
// ... existing code ...
else if (req_.upgrade) {
if (req_.get_header_value("upgrade").substr(0, 2) == "h2") {
// HTTP/2 handling
}
else {
// NEW: Call websocket upgrade hook if registered
constexpr bool is_ssl = !std::is_same<typename Adaptor::context, void>::value;
if (handler_->has_websocket_upgrade_hook()) {
if (!handler_->call_websocket_upgrade_hook(req_, res, is_ssl)) {
// Hook returned false, send response and don't upgrade
// ... send res and return ...
return;
}
}
// Proceed with normal upgrade
close_connection_ = true;
handler_->handle_upgrade(req_, res, std::move(adaptor_));
return;
}
}
}
};Option 2: Extend Middleware System
Allow middleware to intercept WebSocket upgrades by adding a new middleware method:
struct MyMiddleware {
struct context {};
void before_handle(request& req, response& res, context& ctx) {
// Existing middleware for HTTP requests
}
// NEW: Handle WebSocket upgrade requests
bool before_websocket_upgrade(request& req, response& res, context& ctx, bool is_ssl) {
if (!is_ssl) {
res.code = 308;
res.set_header("Location", "wss://...");
return false; // Don't proceed with upgrade
}
return true; // Proceed with upgrade
}
};Option 3: WebSocket-Specific Middleware
Introduce a new middleware type specifically for WebSocket handling:
struct WebSocketUpgradeMiddleware {
struct context {};
// Called before WebSocket upgrade
bool before_upgrade(request& req, response& res, context& ctx, bool is_ssl) {
// Return true to proceed, false to abort and send res
return true;
}
// Optional: Called after successful upgrade
void after_upgrade(websocket::connection& conn, context& ctx) {
// Post-upgrade logic
}
};
// Usage
crow::App<crow::CORSHandler, WebSocketUpgradeMiddleware> app;Benefits
- No library patching needed - Users can implement custom WebSocket upgrade logic without modifying Crow
- Consistent with existing patterns - Similar to how middleware works for HTTP requests
- Flexible - Supports various use cases (redirects, auth, rate limiting, etc.)
- Type-safe - Can provide SSL status information to the hook
- Backward compatible - Optional feature that doesn't affect existing code
Current Workaround
Currently, users must patch Crow's Connection::handle() method directly to implement custom WebSocket upgrade logic, which:
- Makes upgrading Crow difficult
- Requires maintaining a fork
- Isn't portable across projects
Related Code Locations
Connection::handle()method (around line 9105 in crow_all.h)- WebSocket upgrade logic in
handle_upgrade() - Middleware system implementation
Questions for Maintainers
- Which implementation approach would you prefer?
- Should this be part of the existing middleware system or a separate mechanism?
- Would you like me to submit a PR implementing this feature?
Additional Context
This feature would make Crow more flexible for production deployments where WebSocket connections need custom handling before upgrade, without requiring infrastructure-level solutions (reverse proxies, load balancers, etc.).