From cbbcee0df8f224b330daa634fefa64725f2b0a4b Mon Sep 17 00:00:00 2001 From: Alex Hultman Date: Wed, 27 Dec 2023 20:26:24 +0100 Subject: [PATCH] Add getParameter(name), ParameterRoutes example --- build.c | 2 +- examples/ParameterRoutes.cpp | 28 ++++++++++++++++++++++++++++ src/HttpContext.h | 19 ++++++++++++++++++- src/HttpParser.h | 16 ++++++++++++++++ 4 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 examples/ParameterRoutes.cpp diff --git a/build.c b/build.c index 2acdd58..bafcc8c 100644 --- a/build.c +++ b/build.c @@ -10,7 +10,7 @@ int main(int argc, char **argv) { char *EXEC_SUFFIX = strcpy(calloc(1024, 1), maybe(getenv("EXEC_SUFFIX"))); char *EXAMPLE_FILES[] = {"Http3Server", "Broadcast", "HelloWorld", "Crc32", "ServerName", - "EchoServer", "BroadcastingEchoServer", "UpgradeSync", "UpgradeAsync"}; + "EchoServer", "BroadcastingEchoServer", "UpgradeSync", "UpgradeAsync", "ParameterRoutes"}; strcat(CXXFLAGS, " -march=native -O3 -Wpedantic -Wall -Wextra -Wsign-conversion -Wconversion -std=c++20 -Isrc -IuSockets/src"); strcat(LDFLAGS, " uSockets/*.o"); diff --git a/examples/ParameterRoutes.cpp b/examples/ParameterRoutes.cpp new file mode 100644 index 0000000..9c8d888 --- /dev/null +++ b/examples/ParameterRoutes.cpp @@ -0,0 +1,28 @@ +#include "App.h" + +/* Note that uWS::SSLApp({options}) is the same as uWS::App() when compiled without SSL support */ + +int main() { + /* Overly simple hello world app */ + uWS::SSLApp({ + .key_file_name = "misc/key.pem", + .cert_file_name = "misc/cert.pem", + .passphrase = "1234" + }).get("/:first/static/:second", [](auto *res, auto *req) { + + res->write("

first is: "); + res->write(req->getParameter("first")); + res->write("

"); + + res->write("

second is: "); + res->write(req->getParameter("second")); + res->end("

"); + + }).listen(3000, [](auto *listen_socket) { + if (listen_socket) { + std::cout << "Listening on port " << 3000 << std::endl; + } + }).run(); + + std::cout << "Failed to listen on port 3000" << std::endl; +} diff --git a/src/HttpContext.h b/src/HttpContext.h index 0049ac2..f66b6ea 100644 --- a/src/HttpContext.h +++ b/src/HttpContext.h @@ -435,10 +435,27 @@ public: return; } - httpContextData->currentRouter->add(methods, pattern, [handler = std::move(handler)](auto *r) mutable { + /* Record this route's parameter offsets */ + std::map> parameterOffsets; + unsigned short offset = 0; + for (unsigned int i = 0; i < pattern.length(); i++) { + if (pattern[i] == ':') { + i++; + unsigned int start = i; + while (i < pattern.length() && pattern[i] != '/') { + i++; + } + parameterOffsets[std::string(pattern.data() + start, i - start)] = offset; + //std::cout << "<" << std::string(pattern.data() + start, i - start) << "> is offset " << offset; + offset++; + } + } + + httpContextData->currentRouter->add(methods, pattern, [handler = std::move(handler), parameterOffsets = std::move(parameterOffsets)](auto *r) mutable { auto user = r->getUserData(); user.httpRequest->setYield(false); user.httpRequest->setParameters(r->getParameters()); + user.httpRequest->setParameterOffsets(¶meterOffsets); /* Middleware? Automatically respond to expectations */ std::string_view expect = user.httpRequest->getHeader("expect"); diff --git a/src/HttpParser.h b/src/HttpParser.h index d3a9b08..e298fe5 100644 --- a/src/HttpParser.h +++ b/src/HttpParser.h @@ -65,6 +65,7 @@ private: bool didYield; BloomFilter bf; std::pair currentParameters; + std::map> *currentParameterOffsets = nullptr; public: bool isAncient() { @@ -165,6 +166,21 @@ public: currentParameters = parameters; } + void setParameterOffsets(std::map> *offsets) { + currentParameterOffsets = offsets; + } + + std::string_view getParameter(std::string_view name) { + if (!currentParameterOffsets) { + return {nullptr, 0}; + } + auto it = currentParameterOffsets->find(name); + if (it == currentParameterOffsets->end()) { + return {nullptr, 0}; + } + return getParameter(it->second); + } + std::string_view getParameter(unsigned short index) { if (currentParameters.first < (int) index) { return {};