74bbdf | 2018-09-28 | Henrik Grubbström (Grubba) | |
inherit "module";
#include <module.h>
#include <request_trace.h>
constant cvs_version = "$Id$";
constant thread_safe = 1;
constant module_name = "WebSockets: Protocol support";
constant module_type = MODULE_FIRST;
constant module_doc = "Adds support for the HTTP extension defined "
"in <a href='http://rfc.roxen.com/6455'>RFC 6455 (WebSocket)</a>.";
constant module_unique = 1;
#ifdef WS_DEBUG
#define WS_WERROR(X...) werror(X)
#else /* !WS_DEBUG */
#define WS_WERROR(X...)
#endif /* WS_DEBUG */
Configuration conf;
void create()
{
}
void start(int q, Configuration c)
{
conf = c;
}
mapping(string:mixed)|int(-1..0) first_try(RequestID id)
{
TRACE_ENTER("Checking if this is a valid websocket request...", this);
if (id->misc->internal_get) {
TRACE_LEAVE("No - internal request.");
return 0;
}
if (id->method != "GET") {
TRACE_LEAVE("No - wrong method.");
return 0;
}
if (!has_prefix(id->prot, "HTTP/") ||
(id->prot[sizeof("HTTP/")..] < "1.1")) {
TRACE_LEAVE("No - not HTTP/1.1 or later.");
return 0;
}
if (!has_value(lower_case(id->request_headers->connection||"")/",",
"upgrade")) {
TRACE_LEAVE("No - no connection: upgrade.");
return 0;
}
if (!has_value(lower_case(id->request_headers->upgrade||"")/",",
"websocket")) {
id->misc->error_code = id->misc->error_code || Protocols.HTTP.HTTP_BAD;
TRACE_LEAVE("No - Unsupported or missing upgrade header.");
return 0;
}
if (id->request_headers["sec-websocket-version"] !=
(string)13) {
TRACE_LEAVE("No - Unsupported websocket version.");
return Roxen.http_status(Protocols.HTTP.HTTP_BAD,
"Unsupported WebSocket version.") + ([
"extra_heads": ([
"Sec-WebSocket-Version": (string)13,
]),
]);
}
string raw_key = "";
catch {
raw_key = MIME.decode_base64(id->request_headers["sec-websocket-key"]);
};
if (sizeof(raw_key) < 16) {
TRACE_LEAVE("No - Invalid Sec-WebSocket-Key.");
return Roxen.http_status(Protocols.HTTP.HTTP_BAD,
"Invalid Sec-WebSocket-Key.");
}
TRACE_LEAVE("Yes.");
id->method = "WebSocketOpen";
id->misc->error_code = Protocols.HTTP.HTTP_BAD;
return 0;
}
|