mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
chore: HttpContext.h cleanup (#24730)
This commit is contained in:
@@ -38,6 +38,56 @@
|
||||
|
||||
|
||||
namespace uWS {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T, typename... Args>
|
||||
[[nodiscard]] constexpr auto makeArray(T&& el0, Args&&... values) noexcept {
|
||||
return std::array<std::decay_t<T>, 1 + sizeof...(Args)>{
|
||||
std::forward<T>(el0), std::forward<Args>(values)...
|
||||
};
|
||||
}
|
||||
|
||||
static constexpr auto supportedHttpMethods = makeArray<std::string_view>(
|
||||
"ACL",
|
||||
"BIND",
|
||||
"CHECKOUT",
|
||||
"CONNECT",
|
||||
"COPY",
|
||||
"DELETE",
|
||||
"GET",
|
||||
"HEAD",
|
||||
"LINK",
|
||||
"LOCK",
|
||||
"M-SEARCH",
|
||||
"MERGE",
|
||||
"MKACTIVITY",
|
||||
"MKCALENDAR",
|
||||
"MKCOL",
|
||||
"MOVE",
|
||||
"NOTIFY",
|
||||
"OPTIONS",
|
||||
"PATCH",
|
||||
"POST",
|
||||
"PROPFIND",
|
||||
"PROPPATCH",
|
||||
"PURGE",
|
||||
"PUT",
|
||||
"QUERY",
|
||||
"REBIND",
|
||||
"REPORT",
|
||||
"SEARCH",
|
||||
"SOURCE",
|
||||
"SUBSCRIBE",
|
||||
"TRACE",
|
||||
"UNBIND",
|
||||
"UNLINK",
|
||||
"UNLOCK",
|
||||
"UNSUBSCRIBE"
|
||||
);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<bool> struct HttpResponse;
|
||||
|
||||
template <bool SSL>
|
||||
@@ -53,78 +103,6 @@ private:
|
||||
/* Minimum allowed receive throughput per second (clients uploading less than 16kB/sec get dropped) */
|
||||
static constexpr int HTTP_RECEIVE_THROUGHPUT_BYTES = 16 * 1024;
|
||||
|
||||
|
||||
#define FOR_EACH_HTTP_METHOD(MACRO) \
|
||||
MACRO("ACL") \
|
||||
MACRO("BIND") \
|
||||
MACRO("CHECKOUT") \
|
||||
MACRO("CONNECT") \
|
||||
MACRO("COPY") \
|
||||
MACRO("DELETE") \
|
||||
MACRO("GET") \
|
||||
MACRO("HEAD") \
|
||||
MACRO("LINK") \
|
||||
MACRO("LOCK") \
|
||||
MACRO("M-SEARCH") \
|
||||
MACRO("MERGE") \
|
||||
MACRO("MKACTIVITY") \
|
||||
MACRO("MKCALENDAR") \
|
||||
MACRO("MKCOL") \
|
||||
MACRO("MOVE") \
|
||||
MACRO("NOTIFY") \
|
||||
MACRO("OPTIONS") \
|
||||
MACRO("PATCH") \
|
||||
MACRO("POST") \
|
||||
MACRO("PROPFIND") \
|
||||
MACRO("PROPPATCH") \
|
||||
MACRO("PURGE") \
|
||||
MACRO("PUT") \
|
||||
MACRO("QUERY") \
|
||||
MACRO("REBIND") \
|
||||
MACRO("REPORT") \
|
||||
MACRO("SEARCH") \
|
||||
MACRO("SOURCE") \
|
||||
MACRO("SUBSCRIBE") \
|
||||
MACRO("TRACE") \
|
||||
MACRO("UNBIND") \
|
||||
MACRO("UNLINK") \
|
||||
MACRO("UNLOCK") \
|
||||
MACRO("UNSUBSCRIBE") \
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
static constexpr std::array<const std::string, 35> HTTP_METHODS = {
|
||||
#define MACRO(name) std::string {name},
|
||||
FOR_EACH_HTTP_METHOD(MACRO)
|
||||
#undef MACRO
|
||||
};
|
||||
static std::span<const std::string> getAllHttpMethods() {
|
||||
return {HTTP_METHODS.data(), HTTP_METHODS.size()};
|
||||
}
|
||||
#else
|
||||
// Windows, and older C++ can't do constexpr std::array<const std::string, 35>
|
||||
static constexpr std::array<const char*, 35> HTTP_METHODS = {
|
||||
#define MACRO(name) name,
|
||||
FOR_EACH_HTTP_METHOD(MACRO)
|
||||
#undef MACRO
|
||||
};
|
||||
|
||||
static std::span<const std::string> getAllHttpMethods() {
|
||||
static std::once_flag flag;
|
||||
static std::array<std::string, 35> methods;
|
||||
std::call_once(flag, []() {
|
||||
methods = {
|
||||
#define MACRO(name) std::string {name},
|
||||
FOR_EACH_HTTP_METHOD(MACRO)
|
||||
#undef MACRO
|
||||
};
|
||||
});
|
||||
return {methods.data(), methods.size()};
|
||||
}
|
||||
#endif
|
||||
#undef FOR_EACH_HTTP_METHOD
|
||||
|
||||
|
||||
us_socket_context_t *getSocketContext() {
|
||||
return (us_socket_context_t *) this;
|
||||
}
|
||||
@@ -195,7 +173,7 @@ private:
|
||||
|
||||
/* Call filter */
|
||||
HttpContextData<SSL> *httpContextData = getSocketContextDataS(s);
|
||||
|
||||
|
||||
if(httpResponseData && httpResponseData->isConnectRequest) {
|
||||
if (httpResponseData->socketData && httpContextData->onSocketData) {
|
||||
httpContextData->onSocketData(httpResponseData->socketData, SSL, s, "", 0, true);
|
||||
@@ -203,7 +181,7 @@ private:
|
||||
if(httpResponseData->inStream) {
|
||||
httpResponseData->inStream(reinterpret_cast<HttpResponse<SSL> *>(s), "", 0, true, httpResponseData->userData);
|
||||
httpResponseData->inStream = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -253,7 +231,7 @@ private:
|
||||
/* Mark that we are inside the parser now */
|
||||
httpContextData->flags.isParsingHttp = true;
|
||||
httpResponseData->isIdle = false;
|
||||
|
||||
|
||||
// clients need to know the cursor after http parse, not servers!
|
||||
// how far did we read then? we need to know to continue with websocket parsing data? or?
|
||||
|
||||
@@ -266,7 +244,7 @@ private:
|
||||
|
||||
auto result = httpResponseData->consumePostPadded(httpContextData->maxHeaderSize, httpResponseData->isConnectRequest, httpContextData->flags.requireHostHeader,httpContextData->flags.useStrictMethodValidation, data, (unsigned int) length, s, proxyParser, [httpContextData](void *s, 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! */
|
||||
us_socket_timeout(SSL, (us_socket_t *) s, 0);
|
||||
@@ -465,7 +443,7 @@ private:
|
||||
us_socket_context_on_writable(SSL, getSocketContext(), [](us_socket_t *s) {
|
||||
auto *asyncSocket = reinterpret_cast<AsyncSocket<SSL> *>(s);
|
||||
auto *httpResponseData = reinterpret_cast<HttpResponseData<SSL> *>(asyncSocket->getAsyncSocketData());
|
||||
|
||||
|
||||
/* Attempt to drain the socket buffer before triggering onWritable callback */
|
||||
size_t bufferedAmount = asyncSocket->getBufferedAmount();
|
||||
if (bufferedAmount > 0) {
|
||||
@@ -536,7 +514,7 @@ private:
|
||||
us_socket_context_on_end(SSL, getSocketContext(), [](us_socket_t *s) {
|
||||
auto *asyncSocket = reinterpret_cast<AsyncSocket<SSL> *>(s);
|
||||
asyncSocket->uncorkWithoutSending();
|
||||
|
||||
|
||||
/* We do not care for half closed sockets */
|
||||
return asyncSocket->close();
|
||||
});
|
||||
@@ -602,14 +580,16 @@ public:
|
||||
void onHttp(std::string_view method, std::string_view pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler, bool upgrade = false) {
|
||||
HttpContextData<SSL> *httpContextData = getSocketContextData();
|
||||
|
||||
std::span<const std::string> methods;
|
||||
std::array<std::string, 1> methods_buffer;
|
||||
std::span<const std::string_view> methods;
|
||||
std::string method_buffer;
|
||||
std::string_view method_sv_buffer;
|
||||
// When it's NOT node:http, allow the uWS default precedence ordering.
|
||||
if (method == "*" && !httpContextData->flags.useStrictMethodValidation) {
|
||||
methods = getAllHttpMethods();
|
||||
methods = detail::supportedHttpMethods;
|
||||
} else {
|
||||
methods_buffer[0] = std::string(method);
|
||||
methods = {methods_buffer.data(), 1};
|
||||
method_buffer = std::string(method);
|
||||
method_sv_buffer = std::string_view(method_buffer);
|
||||
methods = {&method_sv_buffer, 1};
|
||||
}
|
||||
|
||||
uint32_t priority = method == "*" ? httpContextData->currentRouter->LOW_PRIORITY : (upgrade ? httpContextData->currentRouter->HIGH_PRIORITY : httpContextData->currentRouter->MEDIUM_PRIORITY);
|
||||
|
||||
@@ -33,13 +33,13 @@
|
||||
|
||||
namespace uWS {
|
||||
|
||||
template <class USERDATA>
|
||||
template <typename UserDataType>
|
||||
struct HttpRouter {
|
||||
static constexpr std::string_view ANY_METHOD_TOKEN = "*";
|
||||
static constexpr uint32_t HIGH_PRIORITY = 0xd0000000, MEDIUM_PRIORITY = 0xe0000000, LOW_PRIORITY = 0xf0000000;
|
||||
|
||||
private:
|
||||
USERDATA userData;
|
||||
UserDataType userData;
|
||||
static const unsigned int MAX_URL_SEGMENTS = 100;
|
||||
|
||||
/* Handler ids are 32-bit */
|
||||
@@ -60,8 +60,8 @@ private:
|
||||
std::vector<uint32_t> handlers = {};
|
||||
bool isHighPriority = false;
|
||||
|
||||
Node(std::string name) : name(std::move(name)) {}
|
||||
} root = {"rootNode"};
|
||||
explicit constexpr Node(std::string name) noexcept : name(std::move(name)) {}
|
||||
} root {"rootNode"};
|
||||
|
||||
/* Sort wildcards after alphanum */
|
||||
int lexicalOrder(std::string_view name) {
|
||||
@@ -78,7 +78,7 @@ private:
|
||||
}
|
||||
|
||||
/* Advance from parent to child, adding child if necessary */
|
||||
Node *getNode(Node *parent, std::string child, bool isHighPriority) {
|
||||
Node *getNode(Node *parent, std::string_view child, bool isHighPriority) {
|
||||
for (const std::unique_ptr<Node> &node : parent->children) {
|
||||
if (node->name == child && node->isHighPriority == isHighPriority) {
|
||||
return node.get();
|
||||
@@ -86,7 +86,7 @@ private:
|
||||
}
|
||||
|
||||
/* Insert sorted, but keep order if parent is root (we sort methods by priority elsewhere) */
|
||||
std::unique_ptr<Node> newNode(new Node(child));
|
||||
auto newNode = std::make_unique<Node>(std::string(child));
|
||||
newNode->isHighPriority = isHighPriority;
|
||||
auto iter = std::upper_bound(parent->children.begin(), parent->children.end(), newNode, [parent, this](auto &a, auto &b) {
|
||||
if (a->isHighPriority != b->isHighPriority) {
|
||||
@@ -120,7 +120,7 @@ private:
|
||||
} routeParameters;
|
||||
|
||||
/* Set URL for router. Will reset any URL cache */
|
||||
inline void setUrl(std::string_view url) {
|
||||
void setUrl(std::string_view url) {
|
||||
|
||||
/* Todo: URL may also start with "http://domain/" or "*", not only "/" */
|
||||
|
||||
@@ -130,7 +130,7 @@ private:
|
||||
}
|
||||
|
||||
/* Lazily parse or read from cache */
|
||||
inline std::pair<std::string_view, bool> getUrlSegment(int urlSegment) {
|
||||
std::pair<std::string_view, bool> getUrlSegment(int urlSegment) {
|
||||
if (urlSegment > urlSegmentTop) {
|
||||
/* Signal as STOP when we have no more URL or stack space */
|
||||
if (!currentUrl.length() || urlSegment > int(MAX_URL_SEGMENTS - 1)) {
|
||||
@@ -164,7 +164,7 @@ private:
|
||||
}
|
||||
|
||||
/* Executes as many handlers it can */
|
||||
bool executeHandlers(Node *parent, int urlSegment, USERDATA &userData) {
|
||||
bool executeHandlers(Node *parent, int urlSegment, UserDataType &userData) {
|
||||
|
||||
auto [segment, isStop] = getUrlSegment(urlSegment);
|
||||
|
||||
@@ -248,7 +248,7 @@ public:
|
||||
return {routeParameters.paramsTop, routeParameters.params};
|
||||
}
|
||||
|
||||
USERDATA &getUserData() {
|
||||
UserDataType &getUserData() {
|
||||
return userData;
|
||||
}
|
||||
|
||||
@@ -278,11 +278,11 @@ public:
|
||||
}
|
||||
|
||||
/* Adds the corresponding entires in matching tree and handler list */
|
||||
void add(const std::span<const std::string> &methods, std::string_view pattern, MoveOnlyFunction<bool(HttpRouter *)> &&handler, uint32_t priority = MEDIUM_PRIORITY) {
|
||||
void add(std::span<const std::string_view> methods, std::string_view pattern, MoveOnlyFunction<bool(HttpRouter *)> &&handler, uint32_t priority = MEDIUM_PRIORITY) {
|
||||
/* First remove existing handler */
|
||||
remove(methods[0], pattern, priority);
|
||||
|
||||
for (const std::string &method : methods) {
|
||||
for (const std::string_view method : methods) {
|
||||
/* Lookup method */
|
||||
Node *node = getNode(&root, method, false);
|
||||
/* Iterate over all segments */
|
||||
@@ -381,4 +381,4 @@ public:
|
||||
|
||||
}
|
||||
|
||||
#endif // UWS_HTTPROUTER_HPP
|
||||
#endif // UWS_HTTPROUTER_HPP
|
||||
|
||||
Reference in New Issue
Block a user