mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-22 01:11:42 +00:00
This can be dangerous as it refers to a temporary, and GCC 9.0 warns about its use. Instead add std::initializer_list overloads to common places it was used in an initializer_list sense.
181 lines
5.7 KiB
C++
181 lines
5.7 KiB
C++
/*----------------------------------------------------------------------------*/
|
|
/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
|
|
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
|
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
|
/* the project. */
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
#ifndef WPIUTIL_WPI_WEBSOCKETSERVER_H_
|
|
#define WPIUTIL_WPI_WEBSOCKETSERVER_H_
|
|
|
|
#include <functional>
|
|
#include <initializer_list>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <utility>
|
|
|
|
#include "wpi/ArrayRef.h"
|
|
#include "wpi/HttpParser.h"
|
|
#include "wpi/Signal.h"
|
|
#include "wpi/SmallString.h"
|
|
#include "wpi/SmallVector.h"
|
|
#include "wpi/StringRef.h"
|
|
#include "wpi/WebSocket.h"
|
|
|
|
namespace wpi {
|
|
|
|
namespace uv {
|
|
class Stream;
|
|
} // namespace uv
|
|
|
|
/**
|
|
* WebSocket HTTP server helper. Handles websocket-specific headers. User
|
|
* must provide the HttpParser.
|
|
*/
|
|
class WebSocketServerHelper {
|
|
public:
|
|
/**
|
|
* Constructor.
|
|
* @param req HttpParser for request
|
|
*/
|
|
explicit WebSocketServerHelper(HttpParser& req);
|
|
|
|
/**
|
|
* Get whether or not this was a websocket upgrade.
|
|
* Only valid during and after the upgrade event.
|
|
*/
|
|
bool IsWebsocket() const { return m_websocket; }
|
|
|
|
/**
|
|
* Try to find a match to the list of sub-protocols provided by the client.
|
|
* The list is priority ordered, so the first match wins.
|
|
* Only valid during and after the upgrade event.
|
|
* @param protocols Acceptable protocols
|
|
* @return Pair; first item is true if a match was made, false if not.
|
|
* Second item is the matched protocol if a match was made, otherwise
|
|
* is empty.
|
|
*/
|
|
std::pair<bool, StringRef> MatchProtocol(ArrayRef<StringRef> protocols);
|
|
|
|
/**
|
|
* Try to find a match to the list of sub-protocols provided by the client.
|
|
* The list is priority ordered, so the first match wins.
|
|
* Only valid during and after the upgrade event.
|
|
* @param protocols Acceptable protocols
|
|
* @return Pair; first item is true if a match was made, false if not.
|
|
* Second item is the matched protocol if a match was made, otherwise
|
|
* is empty.
|
|
*/
|
|
std::pair<bool, StringRef> MatchProtocol(
|
|
std::initializer_list<StringRef> protocols) {
|
|
return MatchProtocol(makeArrayRef(protocols.begin(), protocols.end()));
|
|
}
|
|
|
|
/**
|
|
* Accept the upgrade. Disconnect other readers (such as the HttpParser
|
|
* reader) before calling this. See also WebSocket::CreateServer().
|
|
* @param stream Connection stream
|
|
* @param protocol The subprotocol to send to the client
|
|
*/
|
|
std::shared_ptr<WebSocket> Accept(uv::Stream& stream,
|
|
StringRef protocol = StringRef{}) {
|
|
return WebSocket::CreateServer(stream, m_key, m_version, protocol);
|
|
}
|
|
|
|
bool IsUpgrade() const { return m_gotHost && m_websocket; }
|
|
|
|
/**
|
|
* Upgrade event. Call Accept() to accept the upgrade.
|
|
*/
|
|
sig::Signal<> upgrade;
|
|
|
|
private:
|
|
bool m_gotHost = false;
|
|
bool m_websocket = false;
|
|
SmallVector<std::string, 2> m_protocols;
|
|
SmallString<64> m_key;
|
|
SmallString<16> m_version;
|
|
};
|
|
|
|
/**
|
|
* Dedicated WebSocket server.
|
|
*/
|
|
class WebSocketServer : public std::enable_shared_from_this<WebSocketServer> {
|
|
struct private_init {};
|
|
|
|
public:
|
|
/**
|
|
* Server options.
|
|
*/
|
|
struct ServerOptions {
|
|
/**
|
|
* Checker for URL. Return true if URL should be accepted. By default all
|
|
* URLs are accepted.
|
|
*/
|
|
std::function<bool(StringRef)> checkUrl;
|
|
|
|
/**
|
|
* Checker for Host header. Return true if Host should be accepted. By
|
|
* default all hosts are accepted.
|
|
*/
|
|
std::function<bool(StringRef)> checkHost;
|
|
};
|
|
|
|
/**
|
|
* Private constructor.
|
|
*/
|
|
WebSocketServer(uv::Stream& stream, ArrayRef<StringRef> protocols,
|
|
const ServerOptions& options, const private_init&);
|
|
|
|
/**
|
|
* Starts a dedicated WebSocket server on the provided connection. The
|
|
* connection should be an accepted client stream.
|
|
* This also sets the stream user data to the socket server.
|
|
* A connected event is emitted when the connection is opened.
|
|
* @param stream Connection stream
|
|
* @param protocols Acceptable subprotocols
|
|
* @param options Handshake options
|
|
*/
|
|
static std::shared_ptr<WebSocketServer> Create(
|
|
uv::Stream& stream, ArrayRef<StringRef> protocols = ArrayRef<StringRef>{},
|
|
const ServerOptions& options = ServerOptions{});
|
|
|
|
/**
|
|
* Starts a dedicated WebSocket server on the provided connection. The
|
|
* connection should be an accepted client stream.
|
|
* This also sets the stream user data to the socket server.
|
|
* A connected event is emitted when the connection is opened.
|
|
* @param stream Connection stream
|
|
* @param protocols Acceptable subprotocols
|
|
* @param options Handshake options
|
|
*/
|
|
static std::shared_ptr<WebSocketServer> Create(
|
|
uv::Stream& stream, std::initializer_list<StringRef> protocols,
|
|
const ServerOptions& options = ServerOptions{}) {
|
|
return Create(stream, makeArrayRef(protocols.begin(), protocols.end()),
|
|
options);
|
|
}
|
|
|
|
/**
|
|
* Connected event. First parameter is the URL, second is the websocket.
|
|
*/
|
|
sig::Signal<StringRef, WebSocket&> connected;
|
|
|
|
private:
|
|
uv::Stream& m_stream;
|
|
HttpParser m_req{HttpParser::kRequest};
|
|
WebSocketServerHelper m_helper;
|
|
SmallVector<std::string, 2> m_protocols;
|
|
ServerOptions m_options;
|
|
bool m_aborted = false;
|
|
sig::ScopedConnection m_dataConn;
|
|
sig::ScopedConnection m_errorConn;
|
|
sig::ScopedConnection m_endConn;
|
|
|
|
void Abort(uint16_t code, StringRef reason);
|
|
};
|
|
|
|
} // namespace wpi
|
|
|
|
#endif // WPIUTIL_WPI_WEBSOCKETSERVER_H_
|