From ee2756c88055918af092083b071576c492600ca0 Mon Sep 17 00:00:00 2001 From: Alex Hultman Date: Tue, 11 Sep 2018 21:18:06 +0200 Subject: [PATCH] Add some comments to HttpContext, add ideas about drain/mergeDrain --- main.cpp | 2 ++ src/new_design/AsyncSocket.h | 12 ++++++-- src/new_design/HttpContext.h | 54 ++++++++++++++++++++---------------- 3 files changed, 41 insertions(+), 27 deletions(-) diff --git a/main.cpp b/main.cpp index 3df3b4a..819cf61 100644 --- a/main.cpp +++ b/main.cpp @@ -52,6 +52,8 @@ int main(int argc, char **argv) { // new stuff, hope it sticks together? + + uWS::Loop loop; uWS::HttpContext *httpContext = uWS::HttpContext::create(loop.loop); diff --git a/src/new_design/AsyncSocket.h b/src/new_design/AsyncSocket.h index 9eb8dcc..ecdbd15 100644 --- a/src/new_design/AsyncSocket.h +++ b/src/new_design/AsyncSocket.h @@ -40,12 +40,12 @@ protected: return (LoopData *) us_loop_ext(us_socket_context_loop(us_socket_get_context((SOCKET_TYPE *) this))); } +public: + void *getExt() { return static_dispatch(us_ssl_socket_ext, us_socket_ext)((SOCKET_TYPE *) this); } -public: - // cork should bascially mark corked // if already corked, crash and burn! void cork() { @@ -86,8 +86,14 @@ public: } // when we are writable AND have buffer length, that's a really bad situation that should not happen! - void drain() { + void drain(std::string_view optionalChunk) { + // the question here is: should we recursively copy things to the cork buffer and try and send them off in one go? + // it would work in a recursively manner and since optionalChunk is optional, it would never increase the buffer size + + // this function is called from onWritable and combines any buffered data with the chunk + + // the cunk is optional meaning we do not care to buffer it up } // this one will write up to length and simply leave things be diff --git a/src/new_design/HttpContext.h b/src/new_design/HttpContext.h index 57aab96..38677b5 100644 --- a/src/new_design/HttpContext.h +++ b/src/new_design/HttpContext.h @@ -1,6 +1,8 @@ #ifndef HTTPCONTEXT_H #define HTTPCONTEXT_H +/* This class defines the main behavior of HTTP and emits various events */ + #include "Loop.h" #include "HttpContextData.h" #include "HttpResponseData.h" @@ -15,17 +17,15 @@ template struct HttpResponse; template struct HttpContext : StaticDispatch { - +private: using SOCKET_CONTEXT_TYPE = typename StaticDispatch::SOCKET_CONTEXT_TYPE; using SOCKET_TYPE = typename StaticDispatch::SOCKET_TYPE; using StaticDispatch::static_dispatch; - - static const int HTTP_IDLE_TIMEOUT_S = 10; - -private: HttpContext() = delete; - // helper to get the socket context + /* Maximum delay allowed until an HTTP connection is terminated due to outstanding request (slow loris protection) */ + static const int HTTP_IDLE_TIMEOUT_S = 10; + SOCKET_CONTEXT_TYPE *getSocketContext() { return (SOCKET_CONTEXT_TYPE *) this; } @@ -42,11 +42,11 @@ private: return (HttpContextData *) static_dispatch(us_ssl_socket_context_ext, us_socket_context_ext)(getSocketContext(s)); } -public: - + /* Init the HttpContext by registering libusockets event handlers */ HttpContext *init() { //new (data = (Data *) static_dispatch(us_ssl_socket_context_ext, us_socket_context_ext)(httpServerContext)) Data(); + /* Handle socket connections */ static_dispatch(us_ssl_socket_context_on_open, us_socket_context_on_open)(getSocketContext(), [](auto *s, int is_client) { HttpContextData *httpContextData = getSocketContextData(s); @@ -59,6 +59,7 @@ public: return s; }); + /* Handle socket disconnections */ static_dispatch(us_ssl_socket_context_on_close, us_socket_context_on_close)(getSocketContext(), [](auto *s) { HttpContextData *httpContextData = getSocketContextData(s); @@ -67,6 +68,7 @@ public: return s; }); + /* Handle HTTP data streams */ static_dispatch(us_ssl_socket_context_on_data, us_socket_context_on_data)(getSocketContext(), [](auto *s, char *data, int length) { HttpContextData *httpContextData = getSocketContextData(s); @@ -98,41 +100,40 @@ public: // uncork ((AsyncSocket *) s)->uncork(); + // how do we return a new socket here, from the http route? + // maybe hold upgradedSocket in the loopData and return that? return s; }); + /* Handle HTTP write out */ static_dispatch(us_ssl_socket_context_on_writable, us_socket_context_on_writable)(getSocketContext(), [](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); + AsyncSocket *asyncSocket = (AsyncSocket *) s; - // why? WE should emit this event via the socket data that we access! - //((HttpSocket *) s)->onWritable(); + // get next chunk to send + HttpResponseData *httpResponseData = (HttpResponseData *) asyncSocket->getExt(); + std::string_view chunk = httpResponseData->outStream(httpResponseData->offset); - // 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); - }*/ + // send, including any buffered up + asyncSocket->drain(chunk); return s; }); + /* Handle FIN, HTTP does not support half-closed sockets, so simply close */ static_dispatch(us_ssl_socket_context_on_end, us_socket_context_on_end)(getSocketContext(), [](auto *s) { - std::cout << "Socket was half-closed!" << std::endl; + + // static_dispatch(us_ssl_socket_close, us_socket_close)(s); + AsyncSocket *asyncSocket = (AsyncSocket *) s; + asyncSocket->close(); return s; }); + /* Handle socket timeouts */ static_dispatch(us_ssl_socket_context_on_timeout, us_socket_context_on_timeout)(getSocketContext(), [](auto *s) { if (static_dispatch(us_ssl_socket_is_shut_down, us_socket_is_shut_down)(s)) { @@ -151,6 +152,8 @@ public: return this; } +public: + /* Construct a new HttpContext using specified loop */ static HttpContext *create(us_loop *loop) { HttpContext *httpContext = (HttpContext *) us_create_socket_context(loop, sizeof(HttpContextData)); @@ -158,6 +161,7 @@ public: return httpContext->init(); } + /* Destruct the HttpContext, it does not follow RAII */ void free() { // call destructor! @@ -165,6 +169,7 @@ public: static_dispatch(us_ssl_socket_context_free, us_socket_context_free)(getSocketContext()); } + /* Register an HTTP GET route handler acording to URL pattern */ void onGet(std::string pattern, std::function *, uWS::HttpRequest *)> handler) { HttpContextData *httpContextData = getSocketContextData(); @@ -173,6 +178,7 @@ public: }); } + /* Listen to port using this HttpContext */ void listen(const char *host, int port, int options) { static_dispatch(us_ssl_socket_context_listen, us_socket_context_listen)(getSocketContext(), host, port, options, sizeof(HttpResponseData)); }