From 18c9fe0911513f18a24acf99985505100faf2379 Mon Sep 17 00:00:00 2001 From: Alex Hultman Date: Sun, 2 Sep 2018 21:10:01 +0200 Subject: [PATCH] I forgot what I did --- 15.pro | 17 +- main.cpp | 6 +- src/App.h | 278 ++-------------------------- src/HttpParser.h | 205 --------------------- src/HttpRouter.h | 171 ------------------ src/HttpSocket.h | 176 ------------------ src/Socket.h | 8 + src/WebSocket.h | 56 ------ src/WebSocketProtocol.h | 392 ---------------------------------------- src/libwshandshake.hpp | 131 -------------- src/uWS.h | 6 - 11 files changed, 31 insertions(+), 1415 deletions(-) delete mode 100644 src/HttpParser.h delete mode 100644 src/HttpRouter.h delete mode 100644 src/HttpSocket.h delete mode 100644 src/WebSocket.h delete mode 100644 src/WebSocketProtocol.h delete mode 100644 src/libwshandshake.hpp delete mode 100644 src/uWS.h diff --git a/15.pro b/15.pro index 1f64a74..fd23d61 100644 --- a/15.pro +++ b/15.pro @@ -13,16 +13,17 @@ SOURCES += \ uSockets/src/loop.c HEADERS += \ - src/uWS.h \ - src/HttpRouter.h \ + src/http/HttpRouter.h \ src/Loop.h \ src/App.h \ - src/HttpSocket.h \ - src/HttpParser.h \ - src/libwshandshake.hpp \ - src/WebSocketProtocol.h \ - src/WebSocket.h \ - src/Socket.h + src/http/HttpSocket.h \ + src/http/HttpParser.h \ + src/websocket/libwshandshake.hpp \ + src/websocket/WebSocketProtocol.h \ + src/websocket/WebSocket.h \ + src/Socket.h \ + src/websocket/WebSocketApp.h \ + src/http/HttpApp.h INCLUDEPATH += uSockets/src src #QMAKE_CXXFLAGS += -fsanitize=address diff --git a/main.cpp b/main.cpp index 3a414ce..60a21d0 100644 --- a/main.cpp +++ b/main.cpp @@ -1,4 +1,4 @@ -#include "uWS.h" +#include "App.h" #include #include @@ -81,7 +81,7 @@ int main(int argc, char **argv) { std::cout << "WebSocket connected to /wsApi" << std::endl; - }).onMessage([](auto *ws, auto message/*, auto opCode*/) { + }).onMessage([](auto *ws, auto message/*, auto opCode*/) { std::cout << "WebSocket data: " << message << std::endl; @@ -89,7 +89,7 @@ int main(int argc, char **argv) { }).onClose([](/*auto *ws, int code, auto message*/) { - std::cout << "WebSocket disconnected from /wsApi" << std::endl; + //std::cout << "WebSocket disconnected from /wsApi" << std::endl; }).listen("localhost", 3000, 0); diff --git a/src/App.h b/src/App.h index a494ed2..8cd0cb7 100644 --- a/src/App.h +++ b/src/App.h @@ -2,271 +2,12 @@ #define CONTEXT_H #include "libusockets.h" -#include +#include "websocket/WebSocketApp.h" #include "Loop.h" -#include "HttpSocket.h" -#include "HttpRouter.h" -#include "libwshandshake.hpp" -#include "WebSocket.h" +#include namespace uWS { -template -class AppBase { - -protected: - - static const unsigned int HTTP_IDLE_TIMEOUT_S = 10; - - template - static constexpr typename std::conditional::type *static_dispatch(A *a, B *b) { - if constexpr(SSL) { - return a; - } else { - return b; - } - } - - typedef typename std::conditional::type SOCKET_TYPE; - typedef typename std::conditional::type SOCKET_CONTEXT_TYPE; - typedef typename HttpSocket::Data HTTP_SOCKET_DATA_TYPE; - - // todo_ rename to HttpContextData - struct Data { - Data() { - - // default http handler is a router - onHttpRequest = [this](auto *s, HttpRequest *req) { - UserData user = {s, req}; - r.route("GET", 3, req->getUrl().data(), req->getUrl().length(), &user); - }; - - } - - struct UserData { - HttpSocket *httpSocket; - HttpRequest *httpRequest; - }; - - HttpRouter r; - - std::function *)> onHttpConnection; - std::function *)> onHttpDisconnection; - std::function *, HttpRequest *)> onHttpRequest; - } *data; - - struct WebSocketServerContextData { - - WebSocketServerContextData() { - - } - - std::function *, std::string_view)> onMessage; - - } *webSocketServerContextData; - - // server protocols - SOCKET_CONTEXT_TYPE *httpServerContext; - SOCKET_CONTEXT_TYPE *webSocketServerContext; - - // client protocols (todo?) - - void initWebSocketContexts(us_loop *loop) { - new (webSocketServerContextData = (WebSocketServerContextData *) static_dispatch(us_ssl_socket_context_ext, us_socket_context_ext)(webSocketServerContext)) WebSocketServerContextData(); - - static_dispatch(us_ssl_socket_context_on_data, us_socket_context_on_data)(webSocketServerContext, [](auto *s, char *data, int length) { - WebSocketServerContextData *webSocketServerContextData = (WebSocketServerContextData *) static_dispatch(us_ssl_socket_context_ext, us_socket_context_ext)(static_dispatch(us_ssl_socket_get_context, us_socket_get_context)(s)); - - - ((WebSocket *) s)->onData(data, length/*, webSocketServerContextData->onMessage*/); - - // this is set via the setter? - webSocketServerContextData->onMessage((HttpSocket *) s, std::string_view(data, length)); - - - - return s; - }); - } - - void initHttpContexts(us_loop *loop) { - new (data = (Data *) static_dispatch(us_ssl_socket_context_ext, us_socket_context_ext)(httpServerContext)) Data(); - - static_dispatch(us_ssl_socket_context_on_open, us_socket_context_on_open)(httpServerContext, [](auto *s, int is_client) { - Data *appData = (Data *) static_dispatch(us_ssl_socket_context_ext, us_socket_context_ext)(static_dispatch(us_ssl_socket_get_context, us_socket_get_context)(s)); - - static_dispatch(us_ssl_socket_timeout, us_socket_timeout)(s, HTTP_IDLE_TIMEOUT_S); - - new (static_dispatch(us_ssl_socket_ext, us_socket_ext)(s)) HTTP_SOCKET_DATA_TYPE; - - if (appData->onHttpConnection) { - appData->onHttpConnection((HttpSocket *) s); - } - - return s; - }); - - static_dispatch(us_ssl_socket_context_on_close, us_socket_context_on_close)(httpServerContext, [](auto *s) { - Data *appData = (Data *) static_dispatch(us_ssl_socket_context_ext, us_socket_context_ext)(static_dispatch(us_ssl_socket_get_context, us_socket_get_context)(s)); - - ((HTTP_SOCKET_DATA_TYPE *) static_dispatch(us_ssl_socket_ext, us_socket_ext)(s))->~HTTP_SOCKET_DATA_TYPE(); - - if (appData->onHttpDisconnection) { - appData->onHttpDisconnection((HttpSocket *) s); - } - - return s; - }); - - static_dispatch(us_ssl_socket_context_on_data, us_socket_context_on_data)(httpServerContext, [](auto *s, char *data, int length) { - Data *appData = (Data *) static_dispatch(us_ssl_socket_context_ext, us_socket_context_ext)(static_dispatch(us_ssl_socket_get_context, us_socket_get_context)(s)); - - // warning: should NOT reset timer on any data, ONLY reset data on full HTTP requests! - // warning: if we are in shutdown state, resetting the timer is a security issue! - static_dispatch(us_ssl_socket_timeout, us_socket_timeout)(s, HTTP_IDLE_TIMEOUT_S); - - // onHttpRequest should probably be hard-coded to HttpRouter - ((HttpSocket *) s)->onData(data, length, appData->onHttpRequest); - - // compared to routing directly - //typename Data::UserData user = {(HttpSocket *) s, nullptr}; - //appData->r.route("GET", 3, "/", 1, &user); - - return s; - }); - - static_dispatch(us_ssl_socket_context_on_writable, us_socket_context_on_writable)(httpServerContext, [](auto *s) { - - // what if the client - - // I think it's fair to never mind this one -> if we keep writing data after shutting down then that's an issue for us - static_dispatch(us_ssl_socket_timeout, us_socket_timeout)(s, HTTP_IDLE_TIMEOUT_S); - - ((HttpSocket *) s)->onWritable(); - - return s; - }); - - static_dispatch(us_ssl_socket_context_on_end, us_socket_context_on_end)(httpServerContext, [](auto *s) { - std::cout << "Socket was half-closed!" << std::endl; - - return s; - }); - - static_dispatch(us_ssl_socket_context_on_timeout, us_socket_context_on_timeout)(httpServerContext, [](auto *s) { - - if (static_dispatch(us_ssl_socket_is_shut_down, us_socket_is_shut_down)(s)) { - std::cout << "Forcefully closing socket since shutdown was not answered in time" << std::endl; - static_dispatch(us_ssl_socket_close, us_socket_close)(s); - } else { - std::cout << "Shutting down socket now" << std::endl; - static_dispatch(us_ssl_socket_timeout, us_socket_timeout)(s, HTTP_IDLE_TIMEOUT_S); - static_dispatch(us_ssl_socket_shutdown, us_socket_shutdown)(s); - } - - return s; - - }); - } - -public: - - // for server - void listen(const char *host, int port, int options) { - static_dispatch(us_ssl_socket_context_listen, us_socket_context_listen)(httpServerContext, host, port, options, sizeof(typename HttpSocket::Data)); - } - - AppBase &onPost(std::string pattern, std::function *, HttpRequest *, std::vector *)> handler) { - data->r.add("POST", pattern.c_str(), [handler](typename Data::UserData *user, auto *args) { - handler(user->httpSocket, user->httpRequest, args); - }); - - return *this; - } - - AppBase &onGet(std::string pattern, std::function *, HttpRequest *, std::vector *)> handler) { - data->r.add("GET", pattern.c_str(), [handler](typename Data::UserData *user, auto *args) { - handler(user->httpSocket, user->httpRequest, args); - }); - - return *this; - } - - // why even bother with these? - AppBase &onHttpConnection(std::function *)> handler) { - data->onHttpConnection = handler; - - return *this; - } - - AppBase &onHttpDisconnection(std::function *)> handler) { - data->onHttpDisconnection = handler; - - return *this; - } - - // for client and server? fuck no! - template - AppBase &onWebSocket(std::string pattern, std::function *, HttpRequest *, std::vector *)> handler) { - - // todo: GET should probably be get since the parser only leaves lower case - data->r.add("GET", pattern.c_str(), [this, handler](typename Data::UserData *user, auto *args) { - - std::string_view secWebSocketKey = user->httpRequest->getHeader("sec-websocket-key"); - if (secWebSocketKey.length()) { - - // note: OpenSSL can be used here to speed this up somewhat - char secWebSocketAccept[29] = {}; - WebSocketHandshake::generate(secWebSocketKey.data(), secWebSocketAccept); - - user->httpSocket->writeStatus("101 Switching Protocols") - ->writeHeader("Upgrade", "websocket") - ->writeHeader("Connection", "Upgrade") - ->writeHeader("Sec-WebSocket-Accept", secWebSocketAccept) - ->end(""); - - // todo: transform the socket into a websocket and hand it over - static_dispatch(us_ssl_socket_context_adopt_socket, us_socket_context_adopt_socket)(webSocketServerContext, (SOCKET_TYPE *) user->httpSocket, 0); - - handler(user->httpSocket, user->httpRequest, args); - } else { - // note: this calls the http close handler inline - user->httpSocket->close(); - } - }); - - return *this; - } - - AppBase &onMessage(std::function *, std::string_view)> handler) { - - // actually we dynamically create a new server websocket context when we call onWebSocket! - webSocketServerContextData->onMessage = handler; - - return *this; - } - - AppBase &onClose(std::function) { - - return *this; - } - - ~AppBase() { - } -}; - -class App : public AppBase { - -public: - App() { - httpServerContext = us_create_socket_context(defaultLoop.loop, sizeof(Data)); - initHttpContexts(defaultLoop.loop); - - webSocketServerContext = us_create_socket_context(defaultLoop.loop, sizeof(Data)); // this should not have Data! WebSocketData! - initWebSocketContexts(defaultLoop.loop); - } -}; - class SSLOptions { public: us_ssl_socket_context_options options = {}; @@ -291,17 +32,20 @@ public: } }; -class SSLApp : public AppBase { +class App : public WebSocketApp { public: - SSLApp(SSLOptions &sslOptions) { - httpServerContext = us_create_ssl_socket_context(defaultLoop.loop, sizeof(Data), sslOptions.options); - initHttpContexts(defaultLoop.loop); + App() : WebSocketApp(us_create_socket_context(defaultLoop.loop, sizeof(Data))) { - webSocketServerContext = us_create_ssl_socket_context(defaultLoop.loop, sizeof(Data), sslOptions.options); // this should not have Data! WebSocketData! - initWebSocketContexts(defaultLoop.loop); } +}; +class SSLApp : public WebSocketApp { + +public: + SSLApp(SSLOptions &sslOptions) : WebSocketApp(us_create_ssl_socket_context(defaultLoop.loop, sizeof(Data), sslOptions.options)) { + + } }; } diff --git a/src/HttpParser.h b/src/HttpParser.h deleted file mode 100644 index d80650e..0000000 --- a/src/HttpParser.h +++ /dev/null @@ -1,205 +0,0 @@ -#ifndef HTTPPARSER_H -#define HTTPPARSER_H - -#include -#include -#include - -class HttpRequest { - - friend class HttpParser; - -private: - const static int MAX_HEADERS = 50; - struct Header { - std::string_view key, value; - } headers[MAX_HEADERS]; - int querySeparator; - -public: - std::string_view getHeader(std::string_view header) { - for (Header *h = headers; (++h)->key.length(); ) { - if (h->key.length() == header.length() && !strncmp(h->key.data(), header.data(), header.length())) { - return h->value; - } - } - return std::string_view(nullptr, 0); - } - - // todo: implement this - /*int getHeader(std::string_view header) { - return 0; - }*/ - - std::string_view getUrl() { - return std::string_view(headers->value.data(), querySeparator); - } - - std::string_view getQuery() { - return std::string_view(headers->value.data() + querySeparator, headers->value.length() - querySeparator); - } - -}; - -class HttpParser { - -private: - std::string fallback; - int remainingStreamingBytes = 0; - - const size_t MAX_FALLBACK_SIZE = 1024 * 4; - - static unsigned int toUnsignedInteger(std::string_view str) { - int unsignedIntegerValue = 0; - for (unsigned char c : str) { - unsignedIntegerValue = unsignedIntegerValue * 10 + (c - '0'); - } - return unsignedIntegerValue; - } - - static unsigned int getHeaders(char *postPaddedBuffer, char *end, struct HttpRequest::Header *headers) { - char *preliminaryKey, *preliminaryValue, *start = postPaddedBuffer; - - for (unsigned int i = 0; i < HttpRequest::MAX_HEADERS; i++) { - for (preliminaryKey = postPaddedBuffer; (*postPaddedBuffer != ':') & (*postPaddedBuffer > 32); *(postPaddedBuffer++) |= 32); - if (*postPaddedBuffer == '\r') { - if ((postPaddedBuffer != end) & (postPaddedBuffer[1] == '\n') & (i > 0)) { - headers->key = std::string_view(nullptr, 0); - return (postPaddedBuffer + 2) - start; - } else { - return 0; - } - } else { - headers->key = std::string_view(preliminaryKey, (size_t) (postPaddedBuffer - preliminaryKey)); - for (postPaddedBuffer++; (*postPaddedBuffer == ':' || *postPaddedBuffer < 33) && *postPaddedBuffer != '\r'; postPaddedBuffer++); - preliminaryValue = postPaddedBuffer; - postPaddedBuffer = (char *) memchr(postPaddedBuffer, '\r', end - postPaddedBuffer); - if (postPaddedBuffer && postPaddedBuffer[1] == '\n') { - headers->value = std::string_view(preliminaryValue, (size_t) (postPaddedBuffer - preliminaryValue)); - postPaddedBuffer += 2; - headers++; - } else { - return 0; - } - } - } - return 0; - } - - // the only caller of getHeaders - template - int fenceAndConsumePostPadded(char *data, int length, void *user, HttpRequest *req, std::function &requestHandler, std::function &dataHandler) { - int consumedTotal = 0; - data[length] = '\r'; - - for (int consumed; length && (consumed = getHeaders(data, data + length, req->headers)); ) { - data += consumed; - length -= consumed; - consumedTotal += consumed; - - req->headers->value = std::string_view(req->headers->value.data(), std::max(0, req->headers->value.length() - 9)); - - // querySeparator is untested, todo: go through this - const char *querySeparatorPtr = (const char *) memchr(req->headers->value.data(), '?', req->headers->value.length()); - req->querySeparator = (querySeparatorPtr ? querySeparatorPtr : req->headers->value.data() + req->headers->value.length()) - req->headers->value.data(); - - requestHandler(user, req); - - std::string_view contentLengthString = req->getHeader("content-length"); - if (contentLengthString.length()) { - remainingStreamingBytes = toUnsignedInteger(contentLengthString); - - if (!CONSUME_MINIMALLY) { - int emittable = std::min(remainingStreamingBytes, length); - dataHandler(user, std::string_view(data, emittable)); - remainingStreamingBytes -= emittable; - - data += emittable; - length -= emittable; - consumedTotal += emittable; - } - } - - if (CONSUME_MINIMALLY) { - break; - } - } - return consumedTotal; - } - -public: - - // todo: what can we do with the socket inside the handlers? we need to check on return from any handler if we closed or terminated or upgraded the socket - void consumePostPadded(char *data, int length, void *user, std::function &&requestHandler, std::function &&dataHandler, std::function &&errorHandler) { - - HttpRequest req; - - if (remainingStreamingBytes) { - if (remainingStreamingBytes >= length) { - dataHandler(user, std::string_view(data, length)); - remainingStreamingBytes -= length; - return; - } else { - dataHandler(user, std::string_view(data, remainingStreamingBytes)); - - data += remainingStreamingBytes; - length -= remainingStreamingBytes; - - remainingStreamingBytes = 0; - } - } else if (fallback.length()) { - int had = fallback.length(); - - int maxCopyDistance = std::min(MAX_FALLBACK_SIZE - fallback.length(), (size_t) length); - - fallback.reserve(maxCopyDistance + 32); // padding should be same as libus - fallback.append(data, maxCopyDistance); - - int consumed = fenceAndConsumePostPadded(fallback.data(), fallback.length(), user, &req, requestHandler, dataHandler); - if (consumed) { - - fallback.clear(); - - data += consumed - had; - length -= consumed - had; - - // this is exactly the same as above! - if (remainingStreamingBytes) { - if (remainingStreamingBytes >= length) { - dataHandler(user, std::string_view(data, length)); - remainingStreamingBytes -= length; - return; - } else { - dataHandler(user, std::string_view(data, remainingStreamingBytes)); - - data += remainingStreamingBytes; - length -= remainingStreamingBytes; - - remainingStreamingBytes = 0; - } - } - - } else { - if (fallback.length() == MAX_FALLBACK_SIZE) { - errorHandler(user); - } - return; - } - } - - int consumed = fenceAndConsumePostPadded(data, length, user, &req, requestHandler, dataHandler); - - data += consumed; - length -= consumed; - - if (length) { - if (length < MAX_FALLBACK_SIZE) { - fallback.append(data, length); - } else { - errorHandler(user); - } - } - } -}; - -#endif // HTTPPARSER_H diff --git a/src/HttpRouter.h b/src/HttpRouter.h deleted file mode 100644 index 0eaa764..0000000 --- a/src/HttpRouter.h +++ /dev/null @@ -1,171 +0,0 @@ -#ifndef HTTPROUTER_HPP -#define HTTPROUTER_HPP - -// this header also needs testing and fixing as a separate module - -#include -#include -#include -#include -#include -#include - -template -class HttpRouter { -private: - std::vector *)>> handlers; - std::vector params; - - struct Node { - std::string name; - std::map children; - short handler; - }; - - Node *tree = new Node({"GET", {}, -1}); - std::string compiled_tree; - - void add(std::vector route, short handler) { - Node *parent = tree; - for (std::string node : route) { - if (parent->children.find(node) == parent->children.end()) { - parent->children[node] = new Node({node, {}, handler}); - } - parent = parent->children[node]; - } - } - - unsigned short compile_tree(Node *n) { - unsigned short nodeLength = 6 + n->name.length(); - for (auto c : n->children) { - nodeLength += compile_tree(c.second); - } - - unsigned short nodeNameLength = n->name.length(); - - std::string compiledNode; - compiledNode.append((char *) &nodeLength, sizeof(nodeLength)); - compiledNode.append((char *) &nodeNameLength, sizeof(nodeNameLength)); - compiledNode.append((char *) &n->handler, sizeof(n->handler)); - compiledNode.append(n->name.data(), n->name.length()); - - compiled_tree = compiledNode + compiled_tree; - return nodeLength; - } - - inline const char *find_node(const char *parent_node, const char *name, int name_length) { - unsigned short nodeLength = *(unsigned short *) &parent_node[0]; - unsigned short nodeNameLength = *(unsigned short *) &parent_node[2]; - - //std::cout << "Finding node: <" << std::string(name, name_length) << ">" << std::endl; - - const char *stoppp = parent_node + nodeLength; - for (const char *candidate = parent_node + 6 + nodeNameLength; candidate < stoppp; ) { - - unsigned short nodeLength = *(unsigned short *) &candidate[0]; - unsigned short nodeNameLength = *(unsigned short *) &candidate[2]; - - // whildcard, parameter, equal - if (nodeNameLength == 0) { - return candidate; - } else if (candidate[6] == ':') { - // parameter - - // todo: push this pointer on the stack of args! - params.push_back(std::string_view(name, name_length)); - - return candidate; - } else if (nodeNameLength == name_length && !memcmp(candidate + 6, name, name_length)) { - return candidate; - } - - candidate = candidate + nodeLength; - } - - return nullptr; - } - - // returns next slash from start or end - inline const char *getNextSegment(const char *start, const char *end) { - const char *stop = (const char *) memchr(start, '/', end - start); - return stop ? stop : end; - } - - // should take method also! - inline int lookup(const char *url, int length) { - // all urls start with / - url++; - length--; - - const char *treeStart = (char *) compiled_tree.data(); - - const char *stop, *start = url, *end_ptr = url + length; - do { - stop = getNextSegment(start, end_ptr); - - //std::cout << "Matching(" << std::string(start, stop - start) << ")" << std::endl; - - if(nullptr == (treeStart = find_node(treeStart, start, stop - start))) { - return -1; - } - - start = stop + 1; - } while (stop != end_ptr); - - return *(short *) &treeStart[4]; - } - -public: - HttpRouter() { - // maximum 100 parameters - params.reserve(100); - } - - HttpRouter *add(const char *method, const char *pattern, std::function *)> handler) { - - // step over any initial slash - if (pattern[0] == '/') { - pattern++; - } - - std::vector nodes; - //nodes.push_back(method); - - const char *stop, *start = pattern, *end_ptr = pattern + strlen(pattern); - do { - stop = getNextSegment(start, end_ptr); - - //std::cout << "Segment(" << std::string(start, stop - start) << ")" << std::endl; - - nodes.push_back(std::string(start, stop - start)); - - start = stop + 1; - } while (stop != end_ptr); - - - // if pattern starts with / then move 1+ and run inline slash parser - - add(nodes, handlers.size()); - handlers.push_back(handler); - - compile(); - return this; - } - - void compile() { - compiled_tree.clear(); - compile_tree(tree); - } - - void route(const char *method, unsigned int method_length, const char *url, unsigned int url_length, USERDATA userData) { - - int index = lookup(url, url_length); - if (index != -1) { - handlers[index](userData, ¶ms); - } - - params.clear(); - } -}; - -#endif // HTTPROUTER_HPP diff --git a/src/HttpSocket.h b/src/HttpSocket.h deleted file mode 100644 index 1960932..0000000 --- a/src/HttpSocket.h +++ /dev/null @@ -1,176 +0,0 @@ -#ifndef HTTP_H -#define HTTP_H - -#include "Socket.h" -#include "HttpParser.h" - -#include -#include -#include - -template -struct HttpSocket : Socket { - - const size_t MAX_FALLBACK_SIZE = 4096; - - typedef typename Socket::SOCKET_TYPE SOCKET_TYPE; - using Socket::static_dispatch; - - int u32toa(uint32_t value, char *dst) { - char temp[10]; - char *p = temp; - do { - *p++ = (char) (value % 10) + '0'; - value /= 10; - } while (value > 0); - - int ret = p - temp; - - do { - *dst++ = *--p; - } while (p != temp); - - return ret; - } - - // chunked response will be tricky with this buffering scheme - // if we do not fit, we can always use the header buffer for this (both in and out!) - // put first 8kb chunk in the http buffer, then from there it's the stream's job! - // httpheaders should only have 1 stream in and 1 stream out, but we can have helper wrappers - - struct Data { - HttpParser httpParser; - - std::function inStream; - - // out streaming (.end should be a wrapper of this!) - int offset = 0; - std::function outStream; - }; - - // only this one should be used! - void writeToCorkBuffer(const char *src, int length) { - uWS::Loop::Data *loopData = (uWS::Loop::Data *) us_loop_ext(us_socket_context_loop(us_socket_get_context((us_socket *) this))); - - memcpy(loopData->corkBuffer + loopData->corkOffset, src, length); - loopData->corkOffset += length; - } - - // never rely on this one! - int writeToCorkBufferAndReset(const char *src, int length, int contentLength, bool expectMore) { - uWS::Loop::Data *loopData = (uWS::Loop::Data *) us_loop_ext(us_socket_context_loop(us_socket_get_context((us_socket *) this))); - - memcpy(loopData->corkBuffer + loopData->corkOffset, "Content-Length: ", 16); - loopData->corkOffset += 16; - - loopData->corkOffset += u32toa(contentLength, loopData->corkBuffer + loopData->corkOffset); - - memcpy(loopData->corkBuffer + loopData->corkOffset, "\r\n\r\n", 4); - loopData->corkOffset += 4; - - - memcpy(loopData->corkBuffer + loopData->corkOffset, src, length); - loopData->corkOffset += length; - - int written = static_dispatch(us_ssl_socket_write, us_socket_write)((SOCKET_TYPE *) this, loopData->corkBuffer, loopData->corkOffset, expectMore); - - loopData->corkOffset = 0; - return written; - } - - HttpSocket *writeStatus(std::string_view status) { - writeToCorkBuffer("HTTP/1.1 ", 9); - writeToCorkBuffer(status.data(), status.length()); - writeToCorkBuffer("\r\n", 2); - return this; - } - - HttpSocket *writeHeader(std::string_view key, std::string_view value) { - writeToCorkBuffer(key.data(), key.length()); - writeToCorkBuffer(": ", 2); - writeToCorkBuffer(value.data(), value.length()); - writeToCorkBuffer("\r\n", 2); - return this; - } - - // this should not be anything other than a simple convenience wrapper of streams! - void end(std::string_view data) { - // end should not explicitly flush the cork buffer! delay to when done with all http data! - writeToCorkBufferAndReset(data.data(), data.length(), data.length(), false); - } - - // stream out (todo: fix up large sends and benchmark it again) - void write(std::function cb, int length) { - - std::string_view chunk = cb(0); - - // kopiera upp till (SSL eller icke-ssl) max copy distance - - // om mer än detta, fortsätt skicka - - - // this strategy can be simplified to one, we can even have MAX_COPY_DISTANCE_SSL and MAX_COPY_DISTANCE - if (length < uWS::Loop::MAX_COPY_DISTANCE) { - // what if the streamer cannot return any data? - // then it should return something to pause write, and then start it again - // basically we need throttling - writeToCorkBufferAndReset(chunk.data(), chunk.length(), length, false); - } else { - // copying some data with the headers is a good idea for SSL but probably not for non-SSL - writeToCorkBufferAndReset(chunk.data(), uWS::Loop::MAX_COPY_DISTANCE, length, true); - - // just assume this went fine - Data *httpData = (Data *) static_dispatch(us_ssl_socket_ext, us_socket_ext)((SOCKET_TYPE *) this); - - // write that off! - static_dispatch(us_ssl_socket_write, us_socket_write)((SOCKET_TYPE *) this, chunk.data() + uWS::Loop::MAX_COPY_DISTANCE, chunk.length() - uWS::Loop::MAX_COPY_DISTANCE, 0); - - // if offset is at the end, we are done - if (httpData->offset < length) { - httpData->outStream = cb; - } - } - } - - // this thing should only be reachable from App! - void onWritable() { - Data *httpData = (Data *) static_dispatch(us_ssl_socket_ext, us_socket_ext)((SOCKET_TYPE *) this); - - - // now we start streaming as much as possible in each call! - std::string_view chunk = httpData->outStream(httpData->offset); - - // write that off! - static_dispatch(us_ssl_socket_write, us_socket_write)((SOCKET_TYPE *) this, chunk.data(), chunk.length(), 0); - } - - void onData(char *data, int length, std::function *, HttpRequest *)> &onHttpRequest) { - Data *httpData = (Data *) static_dispatch(us_ssl_socket_ext, us_socket_ext)((SOCKET_TYPE *) this); - - // todo: this is where the HttpSocket binds together HttpParser and HttpRouter into one - httpData->httpParser.consumePostPadded(data, length, this, [&onHttpRequest](void *user, HttpRequest *httpRequest) { - onHttpRequest((HttpSocket *) user, httpRequest); - }, [httpData](void *user, std::string_view data) { - if (httpData->inStream) { - httpData->inStream(data); - } - }, [](void *user) { - std::cout << "INVALID HTTP!" << std::endl; - }); - } - - void read(decltype(Data::inStream) stream) { - Data *httpData = (Data *) static_dispatch(us_ssl_socket_ext, us_socket_ext)((SOCKET_TYPE *) this); - - httpData->inStream = stream; - } - - // typical shared function? - void close() { - static_dispatch(us_ssl_socket_close, us_socket_close)((SOCKET_TYPE *) this); - } - - HttpSocket() = delete; -}; - -#endif // HTTP_H diff --git a/src/Socket.h b/src/Socket.h index 49d889d..03b4eba 100644 --- a/src/Socket.h +++ b/src/Socket.h @@ -17,6 +17,14 @@ struct Socket { } typedef typename std::conditional::type SOCKET_TYPE; + typedef typename std::conditional::type SOCKET_CONTEXT_TYPE; + + + void *getSocketContextExt() { + SOCKET_CONTEXT_TYPE *socketContext = static_dispatch(us_ssl_socket_get_context, us_socket_get_context)((SOCKET_TYPE *) this); + + return static_dispatch(us_ssl_socket_context_ext, us_socket_context_ext)(socketContext); + } }; diff --git a/src/WebSocket.h b/src/WebSocket.h deleted file mode 100644 index f422137..0000000 --- a/src/WebSocket.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef WEBSOCKET_H -#define WEBSOCKET_H - -#include "libusockets.h" -#include "Socket.h" -#include "WebSocketProtocol.h" - -// client or server? -template -struct WebSocket : public Socket { - - struct Data : uWS::WebSocketState { - - }; - - static bool setCompressed(bool enabled) { - return true; - } - - static void forceClose(uWS::WebSocketState *wState) { - - } - - static bool handleFragment(char *data, size_t length, unsigned int remainingBytes, int opCode, bool fin, uWS::WebSocketState *webSocketState) { - - std::cout << std::string_view(data, length) << std::endl; - } - - static bool refusePayloadLength(unsigned int length, uWS::WebSocketState *wState) { - return false; - } - - void onData(char *data, int length) { - //Data *webSocketData = (Data *) static_dispatch(us_ssl_socket_ext, us_socket_ext)((SOCKET_TYPE *) this); - - uWS::WebSocketState d; - - uWS::WebSocketProtocol>::consume(data, length, &d); - - - // todo: this is where the HttpSocket binds together HttpParser and HttpRouter into one - /*httpData->httpParser.consumePostPadded(data, length, this, [&onHttpRequest](void *user, HttpRequest *httpRequest) { - onHttpRequest((HttpSocket *) user, httpRequest); - }, [httpData](void *user, std::string_view data) { - if (httpData->inStream) { - httpData->inStream(data); - } - }, [](void *user) { - std::cout << "INVALID HTTP!" << std::endl; - });*/ - } - - WebSocket() = delete; -}; - -#endif // WEBSOCKET_H diff --git a/src/WebSocketProtocol.h b/src/WebSocketProtocol.h deleted file mode 100644 index 108b5d0..0000000 --- a/src/WebSocketProtocol.h +++ /dev/null @@ -1,392 +0,0 @@ -#ifndef WEBSOCKETPROTOCOL_UWS_H -#define WEBSOCKETPROTOCOL_UWS_H - -#ifdef __linux -#include -#include -#elif __APPLE__ -#include -#define htobe64(x) OSSwapHostToBigInt64(x) -#define be64toh(x) OSSwapBigToHostInt64(x) -#else -#ifdef __MINGW32__ -// Windows has always been tied to LE -#define htobe64(x) __builtin_bswap64(x) -#define be64toh(x) __builtin_bswap64(x) -#else -#define htobe64(x) htonll(x) -#define be64toh(x) ntohll(x) -#endif -#endif - -#include -#include - -namespace uWS { - -enum OpCode : unsigned char { - TEXT = 1, - BINARY = 2, - CLOSE = 8, - PING = 9, - PONG = 10 -}; - -enum { - CLIENT, - SERVER -}; - -// 24 bytes perfectly -template -struct WebSocketState { -public: - static const unsigned int SHORT_MESSAGE_HEADER = isServer ? 6 : 2; - static const unsigned int MEDIUM_MESSAGE_HEADER = isServer ? 8 : 4; - static const unsigned int LONG_MESSAGE_HEADER = isServer ? 14 : 10; - - // 16 bytes - struct State { - unsigned int wantsHead : 1; - unsigned int spillLength : 4; - int opStack : 2; // -1, 0, 1 - unsigned int lastFin : 1; - - // 15 bytes - unsigned char spill[LONG_MESSAGE_HEADER - 1]; - OpCode opCode[2]; - - State() { - wantsHead = true; - spillLength = 0; - opStack = -1; - lastFin = true; - } - - } state; - - // 8 bytes - unsigned int remainingBytes = 0; - char mask[isServer ? 4 : 1]; -}; - -template -class WIN32_EXPORT WebSocketProtocol { -public: - static const unsigned int SHORT_MESSAGE_HEADER = isServer ? 6 : 2; - static const unsigned int MEDIUM_MESSAGE_HEADER = isServer ? 8 : 4; - static const unsigned int LONG_MESSAGE_HEADER = isServer ? 14 : 10; - -protected: - static inline bool isFin(char *frame) {return *((unsigned char *) frame) & 128;} - static inline unsigned char getOpCode(char *frame) {return *((unsigned char *) frame) & 15;} - static inline unsigned char payloadLength(char *frame) {return ((unsigned char *) frame)[1] & 127;} - static inline bool rsv23(char *frame) {return *((unsigned char *) frame) & 48;} - static inline bool rsv1(char *frame) {return *((unsigned char *) frame) & 64;} - - static inline void unmaskImprecise(char *dst, char *src, char *mask, unsigned int length) { - for (unsigned int n = (length >> 2) + 1; n; n--) { - *(dst++) = *(src++) ^ mask[0]; - *(dst++) = *(src++) ^ mask[1]; - *(dst++) = *(src++) ^ mask[2]; - *(dst++) = *(src++) ^ mask[3]; - } - } - - static inline void unmaskImpreciseCopyMask(char *dst, char *src, char *maskPtr, unsigned int length) { - char mask[4] = {maskPtr[0], maskPtr[1], maskPtr[2], maskPtr[3]}; - unmaskImprecise(dst, src, mask, length); - } - - static inline void rotateMask(unsigned int offset, char *mask) { - char originalMask[4] = {mask[0], mask[1], mask[2], mask[3]}; - mask[(0 + offset) % 4] = originalMask[0]; - mask[(1 + offset) % 4] = originalMask[1]; - mask[(2 + offset) % 4] = originalMask[2]; - mask[(3 + offset) % 4] = originalMask[3]; - } - - static inline void unmaskInplace(char *data, char *stop, char *mask) { - while (data < stop) { - *(data++) ^= mask[0]; - *(data++) ^= mask[1]; - *(data++) ^= mask[2]; - *(data++) ^= mask[3]; - } - } - - enum { - SND_CONTINUATION = 1, - SND_NO_FIN = 2, - SND_COMPRESSED = 64 - }; - - template - static inline bool consumeMessage(T payLength, char *&src, unsigned int &length, WebSocketState *wState) { - if (getOpCode(src)) { - if (wState->state.opStack == 1 || (!wState->state.lastFin && getOpCode(src) < 2)) { - Impl::forceClose(wState); - return true; - } - wState->state.opCode[++wState->state.opStack] = (OpCode) getOpCode(src); - } else if (wState->state.opStack == -1) { - Impl::forceClose(wState); - return true; - } - wState->state.lastFin = isFin(src); - - if (Impl::refusePayloadLength(payLength, wState)) { - Impl::forceClose(wState); - return true; - } - - if (payLength + MESSAGE_HEADER <= length) { - if (isServer) { - unmaskImpreciseCopyMask(src + MESSAGE_HEADER - 4, src + MESSAGE_HEADER, src + MESSAGE_HEADER - 4, (unsigned int) payLength); - if (Impl::handleFragment(src + MESSAGE_HEADER - 4, payLength, 0, wState->state.opCode[wState->state.opStack], isFin(src), wState)) { - return true; - } - } else { - if (Impl::handleFragment(src + MESSAGE_HEADER, payLength, 0, wState->state.opCode[wState->state.opStack], isFin(src), wState)) { - return true; - } - } - - if (isFin(src)) { - wState->state.opStack--; - } - - src += payLength + MESSAGE_HEADER; - length -= payLength + MESSAGE_HEADER; - wState->state.spillLength = 0; - return false; - } else { - wState->state.spillLength = 0; - wState->state.wantsHead = false; - wState->remainingBytes = (unsigned int) (payLength - length + MESSAGE_HEADER); - bool fin = isFin(src); - if (isServer) { - memcpy(wState->mask, src + MESSAGE_HEADER - 4, 4); - unmaskImprecise(src, src + MESSAGE_HEADER, wState->mask, length - MESSAGE_HEADER); - rotateMask(4 - (length - MESSAGE_HEADER) % 4, wState->mask); - } else { - src += MESSAGE_HEADER; - } - Impl::handleFragment(src, length - MESSAGE_HEADER, wState->remainingBytes, wState->state.opCode[wState->state.opStack], fin, wState); - return true; - } - } - - static inline bool consumeContinuation(char *&src, unsigned int &length, WebSocketState *wState) { - if (wState->remainingBytes <= length) { - if (isServer) { - int n = wState->remainingBytes >> 2; - unmaskInplace(src, src + n * 4, wState->mask); - for (int i = 0, s = wState->remainingBytes % 4; i < s; i++) { - src[n * 4 + i] ^= wState->mask[i]; - } - } - - if (Impl::handleFragment(src, wState->remainingBytes, 0, wState->state.opCode[wState->state.opStack], wState->state.lastFin, wState)) { - return false; - } - - if (wState->state.lastFin) { - wState->state.opStack--; - } - - src += wState->remainingBytes; - length -= wState->remainingBytes; - wState->state.wantsHead = true; - return true; - } else { - if (isServer) { - unmaskInplace(src, src + ((length >> 2) + 1) * 4, wState->mask); - } - - wState->remainingBytes -= length; - if (Impl::handleFragment(src, length, wState->remainingBytes, wState->state.opCode[wState->state.opStack], wState->state.lastFin, wState)) { - return false; - } - - if (isServer && length % 4) { - rotateMask(4 - (length % 4), wState->mask); - } - return false; - } - } - -public: - WebSocketProtocol() { - - } - - // Based on utf8_check.c by Markus Kuhn, 2005 - // https://www.cl.cam.ac.uk/~mgk25/ucs/utf8_check.c - // Optimized for predominantly 7-bit content by Alex Hultman, 2016 - // Licensed as Zlib, like the rest of this project - static bool isValidUtf8(unsigned char *s, size_t length) - { - for (unsigned char *e = s + length; s != e; ) { - if (s + 4 <= e && ((*(uint32_t *) s) & 0x80808080) == 0) { - s += 4; - } else { - while (!(*s & 0x80)) { - if (++s == e) { - return true; - } - } - - if ((s[0] & 0x60) == 0x40) { - if (s + 1 >= e || (s[1] & 0xc0) != 0x80 || (s[0] & 0xfe) == 0xc0) { - return false; - } - s += 2; - } else if ((s[0] & 0xf0) == 0xe0) { - if (s + 2 >= e || (s[1] & 0xc0) != 0x80 || (s[2] & 0xc0) != 0x80 || - (s[0] == 0xe0 && (s[1] & 0xe0) == 0x80) || (s[0] == 0xed && (s[1] & 0xe0) == 0xa0)) { - return false; - } - s += 3; - } else if ((s[0] & 0xf8) == 0xf0) { - if (s + 3 >= e || (s[1] & 0xc0) != 0x80 || (s[2] & 0xc0) != 0x80 || (s[3] & 0xc0) != 0x80 || - (s[0] == 0xf0 && (s[1] & 0xf0) == 0x80) || (s[0] == 0xf4 && s[1] > 0x8f) || s[0] > 0xf4) { - return false; - } - s += 4; - } else { - return false; - } - } - } - return true; - } - - struct CloseFrame { - uint16_t code; - char *message; - size_t length; - }; - - static inline CloseFrame parseClosePayload(char *src, size_t length) { - CloseFrame cf = {}; - if (length >= 2) { - memcpy(&cf.code, src, 2); - cf = {ntohs(cf.code), src + 2, length - 2}; - if (cf.code < 1000 || cf.code > 4999 || (cf.code > 1011 && cf.code < 4000) || - (cf.code >= 1004 && cf.code <= 1006) || !isValidUtf8((unsigned char *) cf.message, cf.length)) { - return {}; - } - } - return cf; - } - - static inline size_t formatClosePayload(char *dst, uint16_t code, const char *message, size_t length) { - if (code) { - code = htons(code); - memcpy(dst, &code, 2); - memcpy(dst + 2, message, length); - return length + 2; - } - return 0; - } - - static inline size_t formatMessage(char *dst, const char *src, size_t length, OpCode opCode, size_t reportedLength, bool compressed) { - size_t messageLength; - size_t headerLength; - if (reportedLength < 126) { - headerLength = 2; - dst[1] = reportedLength; - } else if (reportedLength <= UINT16_MAX) { - headerLength = 4; - dst[1] = 126; - *((uint16_t *) &dst[2]) = htons(reportedLength); - } else { - headerLength = 10; - dst[1] = 127; - *((uint64_t *) &dst[2]) = htobe64(reportedLength); - } - - int flags = 0; - dst[0] = (flags & SND_NO_FIN ? 0 : 128) | (compressed ? SND_COMPRESSED : 0); - if (!(flags & SND_CONTINUATION)) { - dst[0] |= opCode; - } - - char mask[4]; - if (!isServer) { - dst[1] |= 0x80; - uint32_t random = rand(); - memcpy(mask, &random, 4); - memcpy(dst + headerLength, &random, 4); - headerLength += 4; - } - - messageLength = headerLength + length; - memcpy(dst + headerLength, src, length); - - if (!isServer) { - - // overwrites up to 3 bytes outside of the given buffer! - //WebSocketProtocol::unmaskInplace(dst + headerLength, dst + headerLength + length, mask); - - // this is not optimal - char *start = dst + headerLength; - char *stop = start + length; - int i = 0; - while (start != stop) { - (*start++) ^= mask[i++ % 4]; - } - } - return messageLength; - } - - static inline void consume(char *src, unsigned int length, WebSocketState *wState) { - if (wState->state.spillLength) { - src -= wState->state.spillLength; - length += wState->state.spillLength; - memcpy(src, wState->state.spill, wState->state.spillLength); - } - if (wState->state.wantsHead) { - parseNext: - while (length >= SHORT_MESSAGE_HEADER) { - - // invalid reserved bits / invalid opcodes / invalid control frames / set compressed frame - if ((rsv1(src) && !Impl::setCompressed(wState)) || rsv23(src) || (getOpCode(src) > 2 && getOpCode(src) < 8) || - getOpCode(src) > 10 || (getOpCode(src) > 2 && (!isFin(src) || payloadLength(src) > 125))) { - Impl::forceClose(wState); - return; - } - - if (payloadLength(src) < 126) { - if (consumeMessage(payloadLength(src), src, length, wState)) { - return; - } - } else if (payloadLength(src) == 126) { - if (length < MEDIUM_MESSAGE_HEADER) { - break; - } else if(consumeMessage(ntohs(*(uint16_t *) &src[2]), src, length, wState)) { - return; - } - } else if (length < LONG_MESSAGE_HEADER) { - break; - } else if (consumeMessage(be64toh(*(uint64_t *) &src[2]), src, length, wState)) { - return; - } - } - if (length) { - memcpy(wState->state.spill, src, length); - wState->state.spillLength = length; - } - } else if (consumeContinuation(src, length, wState)) { - goto parseNext; - } - } - - static const int CONSUME_POST_PADDING = 4; - static const int CONSUME_PRE_PADDING = LONG_MESSAGE_HEADER - 1; -}; - -} - -#endif // WEBSOCKETPROTOCOL_UWS_H diff --git a/src/libwshandshake.hpp b/src/libwshandshake.hpp deleted file mode 100644 index ac5381a..0000000 --- a/src/libwshandshake.hpp +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (c) 2016 Alex Hultman and contributors - -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. - -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: - -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgement in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. - -#ifndef LIBWSHANDSHAKE_H -#define LIBWSHANDSHAKE_H - -#include -#include - -class WebSocketHandshake { - template - struct static_for { - void operator()(uint32_t *a, uint32_t *b) { - static_for()(a, b); - T::template f(a, b); - } - }; - - template - struct static_for<0, T> { - void operator()(uint32_t *a, uint32_t *hash) {} - }; - - template - struct Sha1Loop { - static inline uint32_t rol(uint32_t value, size_t bits) {return (value << bits) | (value >> (32 - bits));} - static inline uint32_t blk(uint32_t b[16], size_t i) { - return rol(b[(i + 13) & 15] ^ b[(i + 8) & 15] ^ b[(i + 2) & 15] ^ b[i], 1); - } - - template - static inline void f(uint32_t *a, uint32_t *b) { - switch (state) { - case 1: - a[i % 5] += ((a[(3 + i) % 5] & (a[(2 + i) % 5] ^ a[(1 + i) % 5])) ^ a[(1 + i) % 5]) + b[i] + 0x5a827999 + rol(a[(4 + i) % 5], 5); - a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); - break; - case 2: - b[i] = blk(b, i); - a[(1 + i) % 5] += ((a[(4 + i) % 5] & (a[(3 + i) % 5] ^ a[(2 + i) % 5])) ^ a[(2 + i) % 5]) + b[i] + 0x5a827999 + rol(a[(5 + i) % 5], 5); - a[(4 + i) % 5] = rol(a[(4 + i) % 5], 30); - break; - case 3: - b[(i + 4) % 16] = blk(b, (i + 4) % 16); - a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 4) % 16] + 0x6ed9eba1 + rol(a[(4 + i) % 5], 5); - a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); - break; - case 4: - b[(i + 8) % 16] = blk(b, (i + 8) % 16); - a[i % 5] += (((a[(3 + i) % 5] | a[(2 + i) % 5]) & a[(1 + i) % 5]) | (a[(3 + i) % 5] & a[(2 + i) % 5])) + b[(i + 8) % 16] + 0x8f1bbcdc + rol(a[(4 + i) % 5], 5); - a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); - break; - case 5: - b[(i + 12) % 16] = blk(b, (i + 12) % 16); - a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 12) % 16] + 0xca62c1d6 + rol(a[(4 + i) % 5], 5); - a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); - break; - case 6: - b[i] += a[4 - i]; - } - } - }; - - static inline void sha1(uint32_t hash[5], uint32_t b[16]) { - uint32_t a[5] = {hash[4], hash[3], hash[2], hash[1], hash[0]}; - static_for<16, Sha1Loop<1>>()(a, b); - static_for<4, Sha1Loop<2>>()(a, b); - static_for<20, Sha1Loop<3>>()(a, b); - static_for<20, Sha1Loop<4>>()(a, b); - static_for<20, Sha1Loop<5>>()(a, b); - static_for<5, Sha1Loop<6>>()(a, hash); - } - - static inline void base64(unsigned char *src, char *dst) { - const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - for (int i = 0; i < 18; i += 3) { - *dst++ = b64[(src[i] >> 2) & 63]; - *dst++ = b64[((src[i] & 3) << 4) | ((src[i + 1] & 240) >> 4)]; - *dst++ = b64[((src[i + 1] & 15) << 2) | ((src[i + 2] & 192) >> 6)]; - *dst++ = b64[src[i + 2] & 63]; - } - *dst++ = b64[(src[18] >> 2) & 63]; - *dst++ = b64[((src[18] & 3) << 4) | ((src[19] & 240) >> 4)]; - *dst++ = b64[((src[19] & 15) << 2)]; - *dst++ = '='; - } - -public: - static inline void generate(const char input[24], char output[28]) { - uint32_t b_output[5] = { - 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 - }; - uint32_t b_input[16] = { - 0, 0, 0, 0, 0, 0, 0x32353845, 0x41464135, 0x2d453931, 0x342d3437, 0x44412d39, - 0x3543412d, 0x43354142, 0x30444338, 0x35423131, 0x80000000 - }; - - for (int i = 0; i < 6; i++) { - b_input[i] = (input[4 * i + 3] & 0xff) | (input[4 * i + 2] & 0xff) << 8 | (input[4 * i + 1] & 0xff) << 16 | (input[4 * i + 0] & 0xff) << 24; - } - sha1(b_output, b_input); - uint32_t last_b[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 480}; - sha1(b_output, last_b); - for (int i = 0; i < 5; i++) { - uint32_t tmp = b_output[i]; - char *bytes = (char *) &b_output[i]; - bytes[3] = tmp & 0xff; - bytes[2] = (tmp >> 8) & 0xff; - bytes[1] = (tmp >> 16) & 0xff; - bytes[0] = (tmp >> 24) & 0xff; - } - base64((unsigned char *) b_output, output); - } -}; - -#endif // LIBWSHANDSHAKE_H diff --git a/src/uWS.h b/src/uWS.h deleted file mode 100644 index d083d12..0000000 --- a/src/uWS.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef UWS_H -#define UWS_H - -#include "App.h" - -#endif // UWS_H