Refactor using new uSockets API

This commit is contained in:
Alex Hultman
2019-01-25 14:15:40 +01:00
parent e14461e253
commit d331ec3e45
10 changed files with 107 additions and 198 deletions
+35 -43
View File
@@ -25,7 +25,6 @@
#include "HttpResponseData.h"
#include "AsyncSocket.h"
#include "StaticDispatch.h"
#include <string_view>
#include <functional>
@@ -36,41 +35,38 @@ namespace uWS {
template<bool> struct HttpResponse;
template <bool SSL>
struct HttpContext : StaticDispatch<SSL> {
struct HttpContext {
private:
using SOCKET_CONTEXT_TYPE = typename StaticDispatch<SSL>::SOCKET_CONTEXT_TYPE;
using SOCKET_TYPE = typename StaticDispatch<SSL>::SOCKET_TYPE;
using StaticDispatch<SSL>::static_dispatch;
HttpContext() = delete;
/* Maximum delay allowed until an HTTP connection is terminated due to outstanding request or rejected data (slow loris protection) */
static const int HTTP_IDLE_TIMEOUT_S = 10;
SOCKET_CONTEXT_TYPE *getSocketContext() {
return (SOCKET_CONTEXT_TYPE *) this;
us_new_socket_context_t *getSocketContext() {
return (us_new_socket_context_t *) this;
}
static SOCKET_CONTEXT_TYPE *getSocketContext(SOCKET_TYPE *s) {
return (SOCKET_CONTEXT_TYPE *) static_dispatch(us_ssl_socket_get_context, us_socket_get_context)(s);
static us_new_socket_context_t *getSocketContext(us_new_socket_t *s) {
return (us_new_socket_context_t *) us_new_socket_context(SSL, s);
}
HttpContextData<SSL> *getSocketContextData() {
return (HttpContextData<SSL> *) static_dispatch(us_ssl_socket_context_ext, us_socket_context_ext)(getSocketContext());
return (HttpContextData<SSL> *) us_new_socket_context_ext(SSL, getSocketContext());
}
static HttpContextData<SSL> *getSocketContextDataS(SOCKET_TYPE *s) {
return (HttpContextData<SSL> *) static_dispatch(us_ssl_socket_context_ext, us_socket_context_ext)(getSocketContext(s));
static HttpContextData<SSL> *getSocketContextDataS(us_new_socket_t *s) {
return (HttpContextData<SSL> *) us_new_socket_context_ext(SSL, getSocketContext(s));
}
/* Init the HttpContext by registering libusockets event handlers */
HttpContext<SSL> *init() {
/* Handle socket connections */
static_dispatch(us_ssl_socket_context_on_open, us_socket_context_on_open)(getSocketContext(), [](auto *s, int is_client) {
us_new_socket_context_on_open(SSL, getSocketContext(), [](auto *s, int is_client) {
/* Any connected socket should timeout until it has a request */
static_dispatch(us_ssl_socket_timeout, us_socket_timeout)(s, HTTP_IDLE_TIMEOUT_S);
us_new_socket_timeout(SSL, s, HTTP_IDLE_TIMEOUT_S);
/* Init socket ext */
new (static_dispatch(us_ssl_socket_ext, us_socket_ext)(s)) HttpResponseData<SSL>;
new (us_new_socket_ext(SSL, s)) HttpResponseData<SSL>;
/* Call filter */
HttpContextData<SSL> *httpContextData = getSocketContextDataS(s);
@@ -82,9 +78,9 @@ private:
});
/* Handle socket disconnections */
static_dispatch(us_ssl_socket_context_on_close, us_socket_context_on_close)(getSocketContext(), [](auto *s) {
us_new_socket_context_on_close(SSL, getSocketContext(), [](auto *s) {
/* Get socket ext */
HttpResponseData<SSL> *httpResponseData = (HttpResponseData<SSL> *) static_dispatch(us_ssl_socket_ext, us_socket_ext)(s);
HttpResponseData<SSL> *httpResponseData = (HttpResponseData<SSL> *) us_new_socket_ext(SSL, s);
/* Call filter */
HttpContextData<SSL> *httpContextData = getSocketContextDataS(s);
@@ -104,7 +100,7 @@ private:
});
/* Handle HTTP data streams */
static_dispatch(us_ssl_socket_context_on_data, us_socket_context_on_data)(getSocketContext(), [](auto *s, char *data, int length) {
us_new_socket_context_on_data(SSL, getSocketContext(), [](auto *s, char *data, int length) {
// total overhead is about 210k down to 180k
// ~210k req/sec is the original perf with write in data
@@ -115,11 +111,11 @@ private:
HttpContextData<SSL> *httpContextData = getSocketContextDataS(s);
/* Do not accept any data while in shutdown state */
if (static_dispatch(us_ssl_socket_is_shut_down, us_socket_is_shut_down)((SOCKET_TYPE *) s)) {
if (us_new_socket_is_shut_down(SSL, (us_new_socket_t *) s)) {
return s;
}
HttpResponseData<SSL> *httpResponseData = (HttpResponseData<SSL> *) static_dispatch(us_ssl_socket_ext, us_socket_ext)(s);
HttpResponseData<SSL> *httpResponseData = (HttpResponseData<SSL> *) us_new_socket_ext(SSL, s);
/* Cork this socket */
((AsyncSocket<SSL> *) s)->cork();
@@ -129,16 +125,16 @@ private:
void *returnedSocket = httpResponseData->consumePostPadded(data, length, s, [httpContextData](void *s, uWS::HttpRequest *httpRequest) -> void * {
/* For every request we reset the timeout and hang until user makes action */
/* Warning: if we are in shutdown state, resetting the timer is a security issue! */
static_dispatch(us_ssl_socket_timeout, us_socket_timeout)((SOCKET_TYPE *) s, 0);
us_new_socket_timeout(SSL, (us_new_socket_t *) s, 0);
/* Reset httpResponse */
HttpResponseData<SSL> *httpResponseData = (HttpResponseData<SSL> *) static_dispatch(us_ssl_socket_ext, us_socket_ext)((SOCKET_TYPE *) s);
HttpResponseData<SSL> *httpResponseData = (HttpResponseData<SSL> *) us_new_socket_ext(SSL, (us_new_socket_t *) s);
httpResponseData->offset = 0;
httpResponseData->state = 0;
/* Are we not ready for another request yet? Terminate the connection. */
if (httpResponseData->state & HttpResponseData<SSL>::HTTP_RESPONSE_PENDING) {
static_dispatch(us_ssl_socket_close, us_socket_close)((SOCKET_TYPE *) s);
us_new_socket_close(SSL, (us_new_socket_t *) s);
return nullptr;
}
@@ -151,7 +147,7 @@ private:
/* If first pass failed, we try and match by "any" method */
if (!httpContextData->router.route("*", httpRequest->getUrl(), routerData)) {
/* If second pass fail, we have to force close this socket as we have no handler for it */
static_dispatch(us_ssl_socket_close, us_socket_close)((SOCKET_TYPE *) s);
us_new_socket_close(SSL, (us_new_socket_t *) s);
return nullptr;
}
}
@@ -165,12 +161,12 @@ private:
}
/* Was the socket closed? */
if (us_socket_is_closed((struct us_socket *) s)) {
if (us_new_socket_is_closed(SSL, (struct us_new_socket_t *) s)) {
return nullptr;
}
/* We absolutely have to terminate parsing if shutdown */
if (static_dispatch(us_ssl_socket_is_shut_down, us_socket_is_shut_down)((SOCKET_TYPE *) s)) {
if (us_new_socket_is_shut_down(SSL, (us_new_socket_t *) s)) {
return nullptr;
}
@@ -189,19 +185,19 @@ private:
httpResponseData->inStream(data, fin);
/* Was the socket closed? */
if (us_socket_is_closed((struct us_socket *) user)) {
if (us_new_socket_is_closed(SSL, (struct us_new_socket_t *) user)) {
return nullptr;
}
/* We absolutely have to terminate parsing if shutdown */
if (static_dispatch(us_ssl_socket_is_shut_down, us_socket_is_shut_down)((SOCKET_TYPE *) user)) {
if (us_new_socket_is_shut_down(SSL, (us_new_socket_t *) user)) {
return nullptr;
}
}
return user;
}, [](void *user) {
/* Close any socket on HTTP errors */
static_dispatch(us_ssl_socket_close, us_socket_close)((SOCKET_TYPE *) user);
us_new_socket_close(SSL, (us_new_socket_t *) user);
return nullptr;
});
@@ -214,7 +210,7 @@ private:
((AsyncSocket<SSL> *) s)->timeout(HTTP_IDLE_TIMEOUT_S);
}
return (SOCKET_TYPE *) returnedSocket;
return (us_new_socket_t *) returnedSocket;
}
/* We cannot return nullptr to the underlying stack in any case */
@@ -222,10 +218,10 @@ private:
});
/* Handle HTTP write out (note: SSL_read may trigger this spuriously, the app need to handle spurious calls) */
static_dispatch(us_ssl_socket_context_on_writable, us_socket_context_on_writable)(getSocketContext(), [](auto *s) {
us_new_socket_context_on_writable(SSL, getSocketContext(), [](auto *s) {
/* We are now writable, so hang timeout again */
static_dispatch(us_ssl_socket_timeout, us_socket_timeout)(s, 0);
us_new_socket_timeout(SSL, s, 0);
AsyncSocket<SSL> *asyncSocket = (AsyncSocket<SSL> *) s;
HttpResponseData<SSL> *httpResponseData = (HttpResponseData<SSL> *) asyncSocket->getExt();
@@ -253,7 +249,7 @@ private:
});
/* 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) {
us_new_socket_context_on_end(SSL, getSocketContext(), [](auto *s) {
/* We do not care for half closed sockets */
AsyncSocket<SSL> *asyncSocket = (AsyncSocket<SSL> *) s;
@@ -262,7 +258,7 @@ private:
});
/* Handle socket timeouts, simply close them so to not confuse client with FIN */
static_dispatch(us_ssl_socket_context_on_timeout, us_socket_context_on_timeout)(getSocketContext(), [](auto *s) {
us_new_socket_context_on_timeout(SSL, getSocketContext(), [](auto *s) {
/* Force close rather than gracefully shutdown and risk confusing the client with a complete download */
AsyncSocket<SSL> *asyncSocket = (AsyncSocket<SSL> *) s;
@@ -275,21 +271,17 @@ private:
public:
/* Construct a new HttpContext using specified loop */
static HttpContext *create(Loop *loop, us_ssl_socket_context_options *ssl_options = nullptr) {
static HttpContext *create(Loop *loop, us_new_socket_context_options_t options = {}) {
HttpContext *httpContext;
if constexpr(SSL) {
httpContext = (HttpContext *) us_create_ssl_socket_context((us_loop *) loop, sizeof(HttpContextData<SSL>), *ssl_options);
} else {
httpContext = (HttpContext *) us_create_socket_context((us_loop *) loop, sizeof(HttpContextData<SSL>));
}
httpContext = (HttpContext *) us_new_create_socket_context(SSL, (us_loop *) loop, sizeof(HttpContextData<SSL>), options);
if (!httpContext) {
return nullptr;
}
/* Init socket context data */
new ((HttpContextData<SSL> *) static_dispatch(us_ssl_socket_context_ext, us_socket_context_ext)((SOCKET_CONTEXT_TYPE *) httpContext)) HttpContextData<SSL>();
new ((HttpContextData<SSL> *) us_new_socket_context_ext(SSL, (us_new_socket_context_t *) httpContext)) HttpContextData<SSL>();
return httpContext->init();
}
@@ -300,7 +292,7 @@ public:
httpContextData->~HttpContextData<SSL>();
/* Free the socket context in whole */
static_dispatch(us_ssl_socket_context_free, us_socket_context_free)(getSocketContext());
us_new_socket_context_free(SSL, getSocketContext());
}
void filter(fu2::unique_function<void(HttpResponse<SSL> *, int)> &&filterHandler) {
@@ -333,7 +325,7 @@ public:
/* Listen to port using this HttpContext */
us_listen_socket *listen(const char *host, int port, int options) {
return static_dispatch(us_ssl_socket_context_listen, us_socket_context_listen)(getSocketContext(), host, port, options, sizeof(HttpResponseData<SSL>));
return us_new_socket_context_listen(SSL, getSocketContext(), host, port, options, sizeof(HttpResponseData<SSL>));
}
};