mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
Improve uWS route performance (#17884)
This commit is contained in:
@@ -68,11 +68,11 @@ namespace uWS {
|
||||
int ssl_prefer_low_memory_usage = 0;
|
||||
|
||||
const char **key = nullptr;
|
||||
unsigned int key_count = 0;
|
||||
unsigned int key_count = 0;
|
||||
const char **cert = nullptr;
|
||||
unsigned int cert_count = 0;
|
||||
unsigned int cert_count = 0;
|
||||
const char **ca = nullptr;
|
||||
unsigned int ca_count = 0;
|
||||
unsigned int ca_count = 0;
|
||||
unsigned int secure_options = 0;
|
||||
int reject_unauthorized = 0;
|
||||
int request_cert = 0;
|
||||
@@ -105,7 +105,7 @@ public:
|
||||
|
||||
|
||||
/* Server name */
|
||||
TemplatedApp &&addServerName(std::string hostname_pattern, SocketContextOptions options = {}, bool *success = nullptr) {
|
||||
TemplatedApp &&addServerName(const std::string &hostname_pattern, SocketContextOptions options = {}, bool *success = nullptr) {
|
||||
|
||||
/* Do nothing if not even on SSL */
|
||||
if constexpr (SSL) {
|
||||
@@ -121,8 +121,8 @@ public:
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
TemplatedApp &&removeServerName(std::string hostname_pattern) {
|
||||
|
||||
TemplatedApp &&removeServerName(const std::string &hostname_pattern) {
|
||||
|
||||
/* This will do for now, would be better if us_socket_context_remove_server_name returned the user data */
|
||||
auto *domainRouter = us_socket_context_find_server_name_userdata(SSL, (struct us_socket_context_t *) httpContext, hostname_pattern.c_str());
|
||||
if (domainRouter) {
|
||||
@@ -133,7 +133,7 @@ public:
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
TemplatedApp &&missingServerName(MoveOnlyFunction<void(const char *hostname)> handler) {
|
||||
TemplatedApp &&missingServerName(MoveOnlyFunction<void(const char *hostname)> &&handler) {
|
||||
|
||||
if (!constructorFailed()) {
|
||||
httpContext->getSocketContextData()->missingServerNameHandler = std::move(handler);
|
||||
@@ -294,7 +294,7 @@ public:
|
||||
}
|
||||
|
||||
template <typename UserData>
|
||||
TemplatedApp &&ws(std::string pattern, WebSocketBehavior<UserData> &&behavior) {
|
||||
TemplatedApp &&ws(std::string_view pattern, WebSocketBehavior<UserData> &&behavior) {
|
||||
/* Don't compile if alignment rules cannot be satisfied */
|
||||
static_assert(alignof(UserData) <= LIBUS_EXT_ALIGNMENT,
|
||||
"µWebSockets cannot satisfy UserData alignment requirements. You need to recompile µSockets with LIBUS_EXT_ALIGNMENT adjusted accordingly.");
|
||||
@@ -473,7 +473,7 @@ public:
|
||||
}
|
||||
|
||||
/* Browse to a server name, changing the router to this domain */
|
||||
TemplatedApp &&domain(std::string serverName) {
|
||||
TemplatedApp &&domain(const std::string &serverName) {
|
||||
HttpContextData<SSL> *httpContextData = httpContext->getSocketContextData();
|
||||
|
||||
void *domainRouter = us_socket_context_find_server_name_userdata(SSL, (struct us_socket_context_t *) httpContext, serverName.c_str());
|
||||
@@ -482,46 +482,46 @@ public:
|
||||
} else {
|
||||
httpContextData->currentRouter = &httpContextData->router;
|
||||
}
|
||||
|
||||
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
TemplatedApp &&get(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
|
||||
TemplatedApp &&get(std::string_view pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
|
||||
if (httpContext) {
|
||||
httpContext->onHttp("GET", pattern, std::move(handler));
|
||||
}
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
TemplatedApp &&post(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
|
||||
TemplatedApp &&post(std::string_view pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
|
||||
if (httpContext) {
|
||||
httpContext->onHttp("POST", pattern, std::move(handler));
|
||||
}
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
TemplatedApp &&options(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
|
||||
TemplatedApp &&options(std::string_view pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
|
||||
if (httpContext) {
|
||||
httpContext->onHttp("OPTIONS", pattern, std::move(handler));
|
||||
}
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
TemplatedApp &&del(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
|
||||
TemplatedApp &&del(std::string_view pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
|
||||
if (httpContext) {
|
||||
httpContext->onHttp("DELETE", pattern, std::move(handler));
|
||||
}
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
TemplatedApp &&patch(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
|
||||
TemplatedApp &&patch(std::string_view pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
|
||||
if (httpContext) {
|
||||
httpContext->onHttp("PATCH", pattern, std::move(handler));
|
||||
}
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
TemplatedApp &&put(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
|
||||
TemplatedApp &&put(std::string_view pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
|
||||
if (httpContext) {
|
||||
httpContext->onHttp("PUT", pattern, std::move(handler));
|
||||
}
|
||||
@@ -535,21 +535,21 @@ public:
|
||||
}
|
||||
|
||||
|
||||
TemplatedApp &&head(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
|
||||
TemplatedApp &&head(std::string_view pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
|
||||
if (httpContext) {
|
||||
httpContext->onHttp("HEAD", pattern, std::move(handler));
|
||||
}
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
TemplatedApp &&connect(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
|
||||
TemplatedApp &&connect(std::string_view pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
|
||||
if (httpContext) {
|
||||
httpContext->onHttp("CONNECT", pattern, std::move(handler));
|
||||
}
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
TemplatedApp &&trace(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
|
||||
TemplatedApp &&trace(std::string_view pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
|
||||
if (httpContext) {
|
||||
httpContext->onHttp("TRACE", pattern, std::move(handler));
|
||||
}
|
||||
@@ -557,7 +557,7 @@ public:
|
||||
}
|
||||
|
||||
/* This one catches any method */
|
||||
TemplatedApp &&any(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
|
||||
TemplatedApp &&any(std::string_view pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
|
||||
if (httpContext) {
|
||||
httpContext->onHttp("*", pattern, std::move(handler));
|
||||
}
|
||||
@@ -565,8 +565,8 @@ public:
|
||||
}
|
||||
|
||||
/* Host, port, callback */
|
||||
TemplatedApp &&listen(std::string host, int port, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler) {
|
||||
if (!host.length()) {
|
||||
TemplatedApp &&listen(const std::string &host, int port, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler) {
|
||||
if (host.empty()) {
|
||||
return listen(port, std::move(handler));
|
||||
}
|
||||
handler(httpContext ? httpContext->listen(host.c_str(), port, 0) : nullptr);
|
||||
@@ -574,8 +574,8 @@ public:
|
||||
}
|
||||
|
||||
/* Host, port, options, callback */
|
||||
TemplatedApp &&listen(std::string host, int port, int options, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler) {
|
||||
if (!host.length()) {
|
||||
TemplatedApp &&listen(const std::string &host, int port, int options, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler) {
|
||||
if (host.empty()) {
|
||||
return listen(port, options, std::move(handler));
|
||||
}
|
||||
handler(httpContext ? httpContext->listen(host.c_str(), port, options) : nullptr);
|
||||
@@ -595,13 +595,13 @@ public:
|
||||
}
|
||||
|
||||
/* options, callback, path to unix domain socket */
|
||||
TemplatedApp &&listen(int options, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler, std::string path) {
|
||||
TemplatedApp &&listen(int options, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler, std::string_view path) {
|
||||
handler(httpContext ? httpContext->listen_unix(path.data(), path.length(), options) : nullptr);
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
/* callback, path to unix domain socket */
|
||||
TemplatedApp &&listen(MoveOnlyFunction<void(us_listen_socket_t *)> &&handler, std::string path, int options) {
|
||||
TemplatedApp &&listen(MoveOnlyFunction<void(us_listen_socket_t *)> &&handler, std::string_view path, int options) {
|
||||
handler(httpContext ? httpContext->listen_unix(path.data(), path.length(), options) : nullptr);
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ struct BackPressure {
|
||||
/* Always erase a minimum of 1/32th the current backpressure */
|
||||
if (pendingRemoval > (buffer.length() >> 5)) {
|
||||
buffer.erase(0, pendingRemoval);
|
||||
buffer.shrink_to_fit();
|
||||
pendingRemoval = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,9 +42,9 @@ namespace uWS {
|
||||
/* Reads hex number until CR or out of data to consume. Updates state. Returns bytes consumed. */
|
||||
inline void consumeHexNumber(std::string_view &data, uint64_t &state) {
|
||||
/* Consume everything higher than 32 */
|
||||
while (data.length() && data.data()[0] > 32) {
|
||||
while (data.length() && data[0] > 32) {
|
||||
|
||||
unsigned char digit = (unsigned char)data.data()[0];
|
||||
unsigned char digit = (unsigned char)data[0];
|
||||
if (digit >= 'a') {
|
||||
digit = (unsigned char) (digit - ('a' - ':'));
|
||||
} else if (digit >= 'A') {
|
||||
@@ -67,7 +67,7 @@ namespace uWS {
|
||||
data.remove_prefix(1);
|
||||
}
|
||||
/* Consume everything not /n */
|
||||
while (data.length() && data.data()[0] != '\n') {
|
||||
while (data.length() && data[0] != '\n') {
|
||||
data.remove_prefix(1);
|
||||
}
|
||||
/* Now we stand on \n so consume it and enable size */
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace uWS {
|
||||
//webSocketContext = WebSocketContext<0, false, int>::create();
|
||||
}
|
||||
|
||||
ClientApp &&connect(std::string url, std::string protocol = "") {
|
||||
ClientApp &&connect(std::string_view url, std::string_view protocol = "") {
|
||||
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
@@ -33,8 +33,8 @@ namespace uWS {
|
||||
}
|
||||
|
||||
/* Host, port, callback */
|
||||
H3App &&listen(std::string host, int port, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler) {
|
||||
if (!host.length()) {
|
||||
H3App &&listen(const std::string &host, int port, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler) {
|
||||
if (host.empty()) {
|
||||
return listen(port, std::move(handler));
|
||||
}
|
||||
handler(http3Context ? (us_listen_socket_t *) http3Context->listen(host.c_str(), port) : nullptr);
|
||||
@@ -42,8 +42,8 @@ namespace uWS {
|
||||
}
|
||||
|
||||
/* Host, port, options, callback */
|
||||
H3App &&listen(std::string host, int port, int options, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler) {
|
||||
if (!host.length()) {
|
||||
H3App &&listen(const std::string &host, int port, int options, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler) {
|
||||
if (host.empty()) {
|
||||
return listen(port, options, std::move(handler));
|
||||
}
|
||||
handler(http3Context ? (us_listen_socket_t *) http3Context->listen(host.c_str(), port) : nullptr);
|
||||
@@ -62,63 +62,63 @@ namespace uWS {
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
H3App &&get(std::string pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {
|
||||
H3App &&get(std::string_view pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {
|
||||
if (http3Context) {
|
||||
http3Context->onHttp("GET", pattern, std::move(handler));
|
||||
}
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
H3App &&post(std::string pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {
|
||||
H3App &&post(std::string_view pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {
|
||||
if (http3Context) {
|
||||
http3Context->onHttp("POST", pattern, std::move(handler));
|
||||
}
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
H3App &&options(std::string pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {
|
||||
H3App &&options(std::string_view pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {
|
||||
if (http3Context) {
|
||||
http3Context->onHttp("OPTIONS", pattern, std::move(handler));
|
||||
}
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
H3App &&del(std::string pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {
|
||||
H3App &&del(std::string_view pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {
|
||||
if (http3Context) {
|
||||
http3Context->onHttp("DELETE", pattern, std::move(handler));
|
||||
}
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
H3App &&patch(std::string pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {
|
||||
H3App &&patch(std::string_view pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {
|
||||
if (http3Context) {
|
||||
http3Context->onHttp("PATCH", pattern, std::move(handler));
|
||||
}
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
H3App &&put(std::string pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {
|
||||
H3App &&put(std::string_view pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {
|
||||
if (http3Context) {
|
||||
http3Context->onHttp("PUT", pattern, std::move(handler));
|
||||
}
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
H3App &&head(std::string pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {
|
||||
H3App &&head(std::string_view pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {
|
||||
if (http3Context) {
|
||||
http3Context->onHttp("HEAD", pattern, std::move(handler));
|
||||
}
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
H3App &&connect(std::string pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {
|
||||
H3App &&connect(std::string_view pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {
|
||||
if (http3Context) {
|
||||
http3Context->onHttp("CONNECT", pattern, std::move(handler));
|
||||
}
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
H3App &&trace(std::string pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {
|
||||
H3App &&trace(std::string_view pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {
|
||||
if (http3Context) {
|
||||
http3Context->onHttp("TRACE", pattern, std::move(handler));
|
||||
}
|
||||
@@ -126,7 +126,7 @@ namespace uWS {
|
||||
}
|
||||
|
||||
/* This one catches any method */
|
||||
H3App &&any(std::string pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {
|
||||
H3App &&any(std::string_view pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {
|
||||
if (http3Context) {
|
||||
http3Context->onHttp("*", pattern, std::move(handler));
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace uWS {
|
||||
us_quic_socket_context_on_stream_data(context, [](us_quic_stream_t *s, char *data, int length) {
|
||||
|
||||
Http3ResponseData *responseData = (Http3ResponseData *) us_quic_stream_ext(s);
|
||||
|
||||
|
||||
/* We never emit FIN here */
|
||||
if (responseData->onData) {
|
||||
responseData->onData({data, (size_t) length}, false);
|
||||
@@ -26,7 +26,7 @@ namespace uWS {
|
||||
us_quic_socket_context_on_stream_end(context, [](us_quic_stream_t *s) {
|
||||
|
||||
Http3ResponseData *responseData = (Http3ResponseData *) us_quic_stream_ext(s);
|
||||
|
||||
|
||||
/* Emit FIN to app */
|
||||
if (responseData->onData) {
|
||||
responseData->onData({nullptr, 0}, true);
|
||||
@@ -77,7 +77,7 @@ namespace uWS {
|
||||
|
||||
std::string_view upperCasedMethod = req->getHeader(":method");
|
||||
std::string_view path = req->getHeader(":path");
|
||||
|
||||
|
||||
contextData->router.getUserData() = {(Http3Response *) s, (Http3Request *) nullptr};
|
||||
contextData->router.route(upperCasedMethod, path);
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace uWS {
|
||||
//lsquic_stream_has_unacked_data
|
||||
|
||||
Http3ResponseData *responseData = (Http3ResponseData *) us_quic_stream_ext(s);
|
||||
|
||||
|
||||
if (responseData->onAborted) {
|
||||
responseData->onAborted();
|
||||
}
|
||||
@@ -130,9 +130,9 @@ namespace uWS {
|
||||
}
|
||||
|
||||
// generic for get, post, any, etc
|
||||
void onHttp(std::string method, std::string path, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&cb) {
|
||||
void onHttp(std::string_view method, std::string_view path, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&cb) {
|
||||
// modifies the router we own as part of Http3ContextData, used in callbacks set in init
|
||||
|
||||
|
||||
Http3ContextData *contextData = (Http3ContextData *) us_quic_socket_context_ext((us_quic_socket_context_t *) this);
|
||||
|
||||
/* Todo: This is ugly, fix */
|
||||
@@ -141,7 +141,7 @@ namespace uWS {
|
||||
methods = contextData->router.upperCasedMethods; //bug! needs to be upper cased!
|
||||
// router.upperCasedMethods;
|
||||
} else {
|
||||
methods = {method};
|
||||
methods = {std::string(method)};
|
||||
}
|
||||
|
||||
contextData->router.add(methods, path, [handler = std::move(cb)](HttpRouter<Http3ContextData::RouterData> *router) mutable {
|
||||
|
||||
@@ -66,14 +66,14 @@ private:
|
||||
|
||||
/* Init the HttpContext by registering libusockets event handlers */
|
||||
HttpContext<SSL> *init() {
|
||||
|
||||
|
||||
if(SSL) {
|
||||
// if we are SSL we need to handle the handshake properly
|
||||
us_socket_context_on_handshake(SSL, getSocketContext(), [](us_socket_t *s, int success, struct us_bun_verify_error_t verify_error, void* custom_data) {
|
||||
// if we are closing or already closed, we don't need to do anything
|
||||
if (!us_socket_is_closed(SSL, s) && !us_socket_is_shut_down(SSL, s)) {
|
||||
if (!us_socket_is_closed(SSL, s) && !us_socket_is_shut_down(SSL, s)) {
|
||||
HttpContextData<SSL> *httpContextData = getSocketContextDataS(s);
|
||||
|
||||
|
||||
if(httpContextData->rejectUnauthorized) {
|
||||
if(!success || verify_error.error != 0) {
|
||||
// we failed to handshake, close the socket
|
||||
@@ -92,7 +92,7 @@ private:
|
||||
}
|
||||
}, nullptr);
|
||||
}
|
||||
|
||||
|
||||
/* Handle socket connections */
|
||||
us_socket_context_on_open(SSL, getSocketContext(), [](us_socket_t *s, int /*is_client*/, char */*ip*/, int /*ip_length*/) {
|
||||
/* Init socket ext */
|
||||
@@ -115,7 +115,7 @@ private:
|
||||
us_socket_context_on_close(SSL, getSocketContext(), [](us_socket_t *s, int /*code*/, void */*reason*/) {
|
||||
((AsyncSocket<SSL> *)s)->uncorkWithoutSending();
|
||||
|
||||
|
||||
|
||||
/* Get socket ext */
|
||||
HttpResponseData<SSL> *httpResponseData = (HttpResponseData<SSL> *) us_socket_ext(SSL, s);
|
||||
|
||||
@@ -129,7 +129,7 @@ private:
|
||||
if (httpResponseData->onAborted) {
|
||||
httpResponseData->onAborted((HttpResponse<SSL> *)s, httpResponseData->userData);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Destruct socket ext */
|
||||
httpResponseData->~HttpResponseData<SSL>();
|
||||
@@ -221,7 +221,7 @@ private:
|
||||
}
|
||||
|
||||
/* Was the socket closed? */
|
||||
if (us_socket_is_closed(SSL, (struct us_socket_t *) s)) {
|
||||
if (us_socket_is_closed(SSL, (us_socket_t *) s)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -377,7 +377,7 @@ private:
|
||||
return s;
|
||||
}
|
||||
|
||||
/* We need to drain any remaining buffered data if success == true*/
|
||||
/* We need to drain any remaining buffered data if success == true*/
|
||||
}
|
||||
|
||||
/* Drain any socket buffer, this might empty our backpressure and thus finish the request */
|
||||
@@ -441,7 +441,7 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
// for servers this is only valid when request cert is enabled
|
||||
|
||||
|
||||
/* Init socket context data */
|
||||
auto* httpContextData = new ((HttpContextData<SSL> *) us_socket_context_ext(SSL, (us_socket_context_t *) httpContext)) HttpContextData<SSL>();
|
||||
if(options.request_cert && options.reject_unauthorized) {
|
||||
@@ -465,16 +465,10 @@ public:
|
||||
}
|
||||
|
||||
/* Register an HTTP route handler acording to URL pattern */
|
||||
void onHttp(std::string method, std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler, bool upgrade = false) {
|
||||
HttpContextData<SSL> *httpContextData = getSocketContextData();
|
||||
void onHttp(std::string_view method, std::string_view pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler, bool upgrade = false) {
|
||||
HttpContextData<SSL> *httpContextData = getSocketContextData();
|
||||
|
||||
/* Todo: This is ugly, fix */
|
||||
std::vector<std::string> methods;
|
||||
if (method == "*") {
|
||||
methods = {"*"};
|
||||
} else {
|
||||
methods = {method};
|
||||
}
|
||||
std::vector<std::string> methods{std::string(method)};
|
||||
|
||||
uint32_t priority = method == "*" ? httpContextData->currentRouter->LOW_PRIORITY : (upgrade ? httpContextData->currentRouter->HIGH_PRIORITY : httpContextData->currentRouter->MEDIUM_PRIORITY);
|
||||
|
||||
@@ -495,7 +489,6 @@ public:
|
||||
i++;
|
||||
}
|
||||
parameterOffsets[std::string(pattern.data() + start, i - start)] = offset;
|
||||
//std::cout << "<" << std::string(pattern.data() + start, i - start) << "> is offset " << offset;
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
@@ -529,7 +522,7 @@ public:
|
||||
// we dont depend on libuv ref for keeping it alive
|
||||
if (socket) {
|
||||
us_socket_unref(&socket->s);
|
||||
}
|
||||
}
|
||||
return socket;
|
||||
}
|
||||
|
||||
|
||||
@@ -141,13 +141,13 @@ namespace uWS
|
||||
|
||||
std::string_view getFullUrl()
|
||||
{
|
||||
return std::string_view(headers->value.data(), headers->value.length());
|
||||
return headers->value;
|
||||
}
|
||||
|
||||
/* Hack: this should be getMethod */
|
||||
std::string_view getCaseSensitiveMethod()
|
||||
{
|
||||
return std::string_view(headers->key.data(), headers->key.length());
|
||||
return headers->key;
|
||||
}
|
||||
|
||||
std::string_view getMethod()
|
||||
@@ -158,7 +158,7 @@ namespace uWS
|
||||
((char *)headers->key.data())[i] |= 32;
|
||||
}
|
||||
|
||||
return std::string_view(headers->key.data(), headers->key.length());
|
||||
return headers->key;
|
||||
}
|
||||
|
||||
/* Returns the raw querystring as a whole, still encoded */
|
||||
@@ -167,7 +167,7 @@ namespace uWS
|
||||
if (querySeparator < headers->value.length())
|
||||
{
|
||||
/* Strip the initial ? */
|
||||
return std::string_view(headers->value.data() + querySeparator + 1, headers->value.length() - querySeparator - 1);
|
||||
return headers->value.substr(querySeparator + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -179,9 +179,7 @@ namespace uWS
|
||||
std::string_view getQuery(std::string_view key)
|
||||
{
|
||||
/* Raw querystring including initial '?' sign */
|
||||
std::string_view queryString = std::string_view(headers->value.data() + querySeparator, headers->value.length() - querySeparator);
|
||||
|
||||
return getDecodedQueryValue(key, queryString);
|
||||
return getDecodedQueryValue(key, headers->value.substr(querySeparator));
|
||||
}
|
||||
|
||||
void setParameters(std::pair<int, std::string_view *> parameters)
|
||||
@@ -569,7 +567,7 @@ namespace uWS
|
||||
* From here we return either [consumed, user] for "keep going",
|
||||
* or [consumed, nullptr] for "break; I am closed or upgraded to websocket"
|
||||
* or [whatever, fullptr] for "break and close me, I am a parser error!" */
|
||||
template <int CONSUME_MINIMALLY>
|
||||
template <bool ConsumeMinimally>
|
||||
std::pair<unsigned int, void *> fenceAndConsumePostPadded(char *data, unsigned int length, void *user, void *reserved, HttpRequest *req, MoveOnlyFunction<void *(void *, HttpRequest *)> &requestHandler, MoveOnlyFunction<void *(void *, std::string_view, bool)> &dataHandler) {
|
||||
|
||||
/* How much data we CONSUMED (to throw away) */
|
||||
@@ -669,7 +667,7 @@ namespace uWS
|
||||
|
||||
remainingStreamingBytes = STATE_IS_CHUNKED;
|
||||
/* If consume minimally, we do not want to consume anything but we want to mark this as being chunked */
|
||||
if (!CONSUME_MINIMALLY) {
|
||||
if constexpr (!ConsumeMinimally) {
|
||||
/* Go ahead and parse it (todo: better heuristics for emitting FIN to the app level) */
|
||||
std::string_view dataToConsume(data, length);
|
||||
for (auto chunk : uWS::ChunkIterator(&dataToConsume, &remainingStreamingBytes)) {
|
||||
@@ -686,7 +684,7 @@ namespace uWS
|
||||
}
|
||||
} else if (contentLengthStringLen) {
|
||||
|
||||
if (!CONSUME_MINIMALLY) {
|
||||
if constexpr (!ConsumeMinimally) {
|
||||
unsigned int emittable = (unsigned int) std::min<uint64_t>(remainingStreamingBytes, length);
|
||||
dataHandler(user, std::string_view(data, emittable), emittable == remainingStreamingBytes);
|
||||
remainingStreamingBytes -= emittable;
|
||||
@@ -701,7 +699,7 @@ namespace uWS
|
||||
}
|
||||
|
||||
/* Consume minimally should break as easrly as possible */
|
||||
if (CONSUME_MINIMALLY) {
|
||||
if constexpr (ConsumeMinimally) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -460,7 +460,7 @@ public:
|
||||
writeStatus(HTTP_200_OK);
|
||||
|
||||
/* Do not allow sending 0 chunks, they mark end of response */
|
||||
if (!data.length()) {
|
||||
if (data.empty()) {
|
||||
/* If you called us, then according to you it was fine to call us so it's fine to still call us */
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace uWS {
|
||||
template <class USERDATA>
|
||||
struct HttpRouter {
|
||||
static constexpr std::string_view ANY_METHOD_TOKEN = "*";
|
||||
static const uint32_t HIGH_PRIORITY = 0xd0000000, MEDIUM_PRIORITY = 0xe0000000, LOW_PRIORITY = 0xf0000000;
|
||||
static constexpr uint32_t HIGH_PRIORITY = 0xd0000000, MEDIUM_PRIORITY = 0xe0000000, LOW_PRIORITY = 0xf0000000;
|
||||
|
||||
private:
|
||||
USERDATA userData;
|
||||
@@ -60,12 +60,12 @@ private:
|
||||
std::vector<uint32_t> handlers = {};
|
||||
bool isHighPriority = false;
|
||||
|
||||
Node(std::string name) : name(name) {}
|
||||
Node(std::string name) : name(std::move(name)) {}
|
||||
} root = {"rootNode"};
|
||||
|
||||
/* Sort wildcards after alphanum */
|
||||
int lexicalOrder(std::string &name) {
|
||||
if (!name.length()) {
|
||||
int lexicalOrder(std::string_view name) {
|
||||
if (name.empty()) {
|
||||
return 2;
|
||||
}
|
||||
if (name[0] == ':') {
|
||||
@@ -79,7 +79,7 @@ private:
|
||||
|
||||
/* Advance from parent to child, adding child if necessary */
|
||||
Node *getNode(Node *parent, std::string child, bool isHighPriority) {
|
||||
for (std::unique_ptr<Node> &node : parent->children) {
|
||||
for (const std::unique_ptr<Node> &node : parent->children) {
|
||||
if (node->name == child && node->isHighPriority == isHighPriority) {
|
||||
return node.get();
|
||||
}
|
||||
@@ -88,14 +88,13 @@ private:
|
||||
/* Insert sorted, but keep order if parent is root (we sort methods by priority elsewhere) */
|
||||
std::unique_ptr<Node> newNode(new Node(child));
|
||||
newNode->isHighPriority = isHighPriority;
|
||||
return parent->children.emplace(std::upper_bound(parent->children.begin(), parent->children.end(), newNode, [parent, this](auto &a, auto &b) {
|
||||
|
||||
auto iter = std::upper_bound(parent->children.begin(), parent->children.end(), newNode, [parent, this](auto &a, auto &b) {
|
||||
if (a->isHighPriority != b->isHighPriority) {
|
||||
return a->isHighPriority;
|
||||
}
|
||||
|
||||
return b->name.length() && (parent != &root) && (lexicalOrder(b->name) < lexicalOrder(a->name));
|
||||
}), std::move(newNode))->get();
|
||||
return !b->name.empty() && (parent != &root) && (lexicalOrder(b->name) < lexicalOrder(a->name));
|
||||
});
|
||||
return parent->children.emplace(iter, std::move(newNode))->get();
|
||||
}
|
||||
|
||||
/* Basically a pre-allocated stack */
|
||||
@@ -182,14 +181,14 @@ private:
|
||||
}
|
||||
|
||||
for (auto &p : parent->children) {
|
||||
if (p->name.length() && p->name[0] == '*') {
|
||||
if (p->name.starts_with('*')) {
|
||||
/* Wildcard match (can be seen as a shortcut) */
|
||||
for (uint32_t handler : p->handlers) {
|
||||
if (handlers[handler & HANDLER_MASK](this)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if (p->name.length() && p->name[0] == ':' && segment.length()) {
|
||||
} else if (p->name.starts_with(':') && !segment.empty()) {
|
||||
/* Parameter match */
|
||||
routeParameters.push(segment);
|
||||
if (executeHandlers(p.get(), urlSegment + 1, userData)) {
|
||||
@@ -207,17 +206,17 @@ private:
|
||||
}
|
||||
|
||||
/* Scans for one matching handler, returning the handler and its priority or UINT32_MAX for not found */
|
||||
uint32_t findHandler(std::string method, std::string pattern, uint32_t priority) {
|
||||
for (std::unique_ptr<Node> &node : root.children) {
|
||||
uint32_t findHandler(std::string_view method, std::string_view pattern, uint32_t priority) {
|
||||
for (const std::unique_ptr<Node> &node : root.children) {
|
||||
if (method == node->name) {
|
||||
setUrl(pattern);
|
||||
Node *n = node.get();
|
||||
for (int i = 0; !getUrlSegment(i).second; i++) {
|
||||
/* Go to next segment or quit */
|
||||
std::string segment = std::string(getUrlSegment(i).first);
|
||||
std::string segment(getUrlSegment(i).first);
|
||||
Node *next = nullptr;
|
||||
for (std::unique_ptr<Node> &child : n->children) {
|
||||
if (((segment.length() && child->name.length() && segment[0] == ':' && child->name[0] == ':') || child->name == segment) && child->isHighPriority == (priority == HIGH_PRIORITY)) {
|
||||
for (const std::unique_ptr<Node> &child : n->children) {
|
||||
if (((segment.starts_with(':') && child->name.starts_with(':')) || child->name == segment) && child->isHighPriority == (priority == HIGH_PRIORITY)) {
|
||||
next = child.get();
|
||||
break;
|
||||
}
|
||||
@@ -242,7 +241,7 @@ private:
|
||||
public:
|
||||
HttpRouter() {
|
||||
/* Always have ANY route */
|
||||
getNode(&root, std::string(ANY_METHOD_TOKEN.data(), ANY_METHOD_TOKEN.length()), false);
|
||||
getNode(&root, std::string(ANY_METHOD_TOKEN), false);
|
||||
}
|
||||
|
||||
std::pair<int, std::string_view *> getParameters() {
|
||||
@@ -279,25 +278,26 @@ public:
|
||||
}
|
||||
|
||||
/* Adds the corresponding entires in matching tree and handler list */
|
||||
void add(std::vector<std::string> methods, std::string pattern, MoveOnlyFunction<bool(HttpRouter *)> &&handler, uint32_t priority = MEDIUM_PRIORITY) {
|
||||
void add(const std::vector<std::string> &methods, std::string_view pattern, MoveOnlyFunction<bool(HttpRouter *)> &&handler, uint32_t priority = MEDIUM_PRIORITY) {
|
||||
/* First remove existing handler */
|
||||
remove(methods[0], pattern, priority);
|
||||
|
||||
for (std::string method : methods) {
|
||||
|
||||
for (const std::string &method : methods) {
|
||||
/* Lookup method */
|
||||
Node *node = getNode(&root, method, false);
|
||||
/* Iterate over all segments */
|
||||
setUrl(pattern);
|
||||
for (int i = 0; !getUrlSegment(i).second; i++) {
|
||||
std::string strippedSegment(getUrlSegment(i).first);
|
||||
if (strippedSegment.length() && strippedSegment[0] == ':') {
|
||||
if (strippedSegment.length() > 1 && strippedSegment[0] == ':') {
|
||||
/* Parameter routes must be named only : */
|
||||
strippedSegment = ":";
|
||||
strippedSegment.resize(1);
|
||||
}
|
||||
node = getNode(node, strippedSegment, priority == HIGH_PRIORITY);
|
||||
}
|
||||
/* Insert handler in order sorted by priority (most significant 1 byte) */
|
||||
node->handlers.insert(std::upper_bound(node->handlers.begin(), node->handlers.end(), (uint32_t) (priority | handlers.size())), (uint32_t) (priority | handlers.size()));
|
||||
uint32_t new_priority(priority | handlers.size());
|
||||
node->handlers.insert(std::upper_bound(node->handlers.begin(), node->handlers.end(), new_priority), new_priority);
|
||||
}
|
||||
|
||||
/* Alloate this handler */
|
||||
@@ -359,7 +359,7 @@ public:
|
||||
/* Removes ALL routes with the same handler as can be found with the given parameters.
|
||||
* Removing a wildcard is done by removing ONE OF the methods the wildcard would match with.
|
||||
* Example: If wildcard includes POST, GET, PUT, you can remove ALL THREE by removing GET. */
|
||||
bool remove(std::string method, std::string pattern, uint32_t priority) {
|
||||
bool remove(std::string_view method, std::string_view pattern, uint32_t priority) {
|
||||
uint32_t handler = findHandler(method, pattern, priority);
|
||||
if (handler == UINT32_MAX) {
|
||||
/* Not found or already removed, do nothing */
|
||||
|
||||
Reference in New Issue
Block a user