aboutsummaryrefslogtreecommitdiff
path: root/src/modules/m_websocket.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules/m_websocket.cpp')
-rw-r--r--src/modules/m_websocket.cpp46
1 files changed, 40 insertions, 6 deletions
diff --git a/src/modules/m_websocket.cpp b/src/modules/m_websocket.cpp
index 6cf721424..242ecc372 100644
--- a/src/modules/m_websocket.cpp
+++ b/src/modules/m_websocket.cpp
@@ -35,17 +35,29 @@ static dynamic_reference_nocheck<HashProvider>* sha1;
struct WebSocketConfig
{
+ enum DefaultMode
+ {
+ // Reject connections if a subprotocol is not requested.
+ DM_REJECT,
+
+ // Use binary frames if a subprotocol is not requested.
+ DM_BINARY,
+
+ // Use UTF-8 text frames if a subprotocol is not requested.
+ DM_TEXT
+ };
+
typedef std::vector<std::string> OriginList;
typedef std::vector<std::string> ProxyRanges;
// The HTTP origins that can connect to the server.
OriginList allowedorigins;
+ // The method to use if a subprotocol is not negotiated.
+ DefaultMode defaultmode;
+
// The IP ranges which send trustworthy X-Real-IP or X-Forwarded-For headers.
ProxyRanges proxyranges;
-
- // Whether to send as UTF-8 text instead of binary data.
- bool sendastext;
};
class WebSocketHookProvider : public IOHookProvider
@@ -406,8 +418,10 @@ class WebSocketHook : public IOHookMiddle
irc::spacesepstream protostream(protocolheader.ExtractValue(recvq));
for (std::string proto; protostream.GetToken(proto); )
{
+ bool is_binary = stdalgo::string::equalsci(proto, "binary.inspircd.org");
bool is_text = stdalgo::string::equalsci(proto, "text.inspircd.org");
- if (stdalgo::string::equalsci(proto, "binary.inspircd.org") || is_text)
+
+ if (is_binary || is_text)
{
selectedproto = proto;
sendastext = is_text;
@@ -416,6 +430,12 @@ class WebSocketHook : public IOHookMiddle
}
}
+ if (selectedproto.empty() && config.defaultmode == WebSocketConfig::DM_REJECT)
+ {
+ FailHandshake(sock, "HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n", "WebSocket: Received HTTP request that did not send the Sec-WebSocket-Protocol header");
+ return -1;
+ }
+
HTTPHeaderFinder keyheader;
if (!keyheader.Find(recvq, "Sec-WebSocket-Key:", 18, reqend))
{
@@ -452,11 +472,16 @@ class WebSocketHook : public IOHookMiddle
WebSocketHook(std::shared_ptr<IOHookProvider> Prov, StreamSocket* sock, WebSocketConfig& cfg)
: IOHookMiddle(Prov)
, config(cfg)
- , sendastext(cfg.sendastext)
+ , sendastext(config.defaultmode != WebSocketConfig::DM_BINARY)
{
sock->AddIOHook(this);
}
+ bool IsHookReady() const override
+ {
+ return state == STATE_ESTABLISHED;
+ }
+
ssize_t OnStreamSocketWrite(StreamSocket* sock, StreamSocket::SendQueue& uppersendq) override
{
StreamSocket::SendQueue& mysendq = GetSendQ();
@@ -570,7 +595,16 @@ class ModuleWebSocket : public Module
}
auto tag = ServerInstance->Config->ConfValue("websocket");
- config.sendastext = tag->getBool("sendastext", true);
+
+ const std::string defaultmodestr = tag->getString("defaultmode", tag->getBool("sendastext", true) ? "text" : "binary", 1);
+ if (stdalgo::string::equalsci(defaultmodestr, "reject"))
+ config.defaultmode = WebSocketConfig::DM_REJECT;
+ else if (stdalgo::string::equalsci(defaultmodestr, "binary"))
+ config.defaultmode = WebSocketConfig::DM_BINARY;
+ else if (stdalgo::string::equalsci(defaultmodestr, "text"))
+ config.defaultmode = WebSocketConfig::DM_TEXT;
+ else
+ throw ModuleException(defaultmodestr + " is an invalid value for <websocket:defaultmode>; acceptable values are 'binary', 'text' and 'reject', at " + tag->source.str());
irc::spacesepstream proxyranges(tag->getString("proxyranges"));
for (std::string proxyrange; proxyranges.GetToken(proxyrange); )