diff --git a/examples/ServerName.cpp b/examples/ServerName.cpp index bbade42..9daaf53 100644 --- a/examples/ServerName.cpp +++ b/examples/ServerName.cpp @@ -2,46 +2,26 @@ /* Note that uWS::SSLApp({options}) is the same as uWS::App() when compiled without SSL support */ -struct us_listen_socket_t *globalListenSocket; - int main() { - /* Overly simple hello world app (SNI) */ + /* The SSL context given in SSLApp constructor is the default / catch-all context */ uWS::SSLApp app = uWS::SSLApp({ .key_file_name = "misc/key.pem", .cert_file_name = "misc/cert.pem", .passphrase = "1234" - }).missingServerName([&app](const char *hostname) { - - printf("We are missing server name: <%s>\n", hostname); - - /* Assume it is localhost, so add it */ - app.addServerName("localhost", { - .key_file_name = "../misc/key.pem", - .cert_file_name = "../misc/cert.pem", - .passphrase = "1234" - }); - }).get("/*", [](auto *res, auto */*req*/) { - res->end("Hello world!"); - }).get("/exit", [](auto *res, auto */*req*/) { - res->end("Shutting down!"); - /* We use this to check graceful closedown */ - us_listen_socket_close(1, globalListenSocket); + res->end("Hello from catch-all context!"); + }).addServerName("*.google.*", { + /* Following is the context for *.google.* domain */ + .key_file_name = "misc/key.pem", + .cert_file_name = "misc/cert.pem", + .passphrase = "1234" + }).domain("*.google.*").get("/*", [](auto *res, auto */*req*/) { + res->end("Hello from *.google.* context!"); }).listen(3000, [](auto *listenSocket) { if (listenSocket) { std::cout << "Listening on port " << 3000 << std::endl; - globalListenSocket = listenSocket; } else { std::cout << "Failed to listen on port 3000" << std::endl; } - }); - - /* Let's add a wildcard SNI to begin with */ - app.addServerName("*.google.*", { - .key_file_name = "../misc/key.pem", - .cert_file_name = "../misc/cert.pem", - .passphrase = "1234" - }); - - app.run(); + }).run(); } diff --git a/src/App.h b/src/App.h index 49717b5..3a08eb8 100644 --- a/src/App.h +++ b/src/App.h @@ -104,7 +104,10 @@ public: /* Server name */ TemplatedApp &&addServerName(std::string hostname_pattern, SocketContextOptions options = {}) { - us_socket_context_add_server_name(SSL, (struct us_socket_context_t *) httpContext, hostname_pattern.c_str(), options); + /* First we create a new router for this domain */ + auto *domainRouter = new HttpRouter::RouterData>(); + + us_socket_context_add_server_name(SSL, (struct us_socket_context_t *) httpContext, hostname_pattern.c_str(), options, domainRouter); return std::move(*this); } @@ -407,6 +410,22 @@ public: return std::move(*this); } + /* Browse to a server name, changing the router to this domain */ + TemplatedApp &&domain(std::string serverName) { + HttpContextData *httpContextData = httpContext->getSocketContextData(); + + void *domainRouter = us_socket_context_find_server_name_userdata(SSL, (struct us_socket_context_t *) httpContext, serverName.c_str()); + if (domainRouter) { + std::cout << "Browsed to SNI: " << serverName << std::endl; + httpContextData->currentRouter = (decltype(httpContextData->currentRouter)) domainRouter; + } else { + std::cout << "Cannot browse to SNI: " << serverName << std::endl; + httpContextData->currentRouter = &httpContextData->router; + } + + return std::move(*this); + } + TemplatedApp &&get(std::string pattern, MoveOnlyFunction *, HttpRequest *)> &&handler) { if (httpContext) { httpContext->onHttp("get", pattern, std::move(handler)); diff --git a/src/HttpContext.h b/src/HttpContext.h index a759255..0f8384b 100644 --- a/src/HttpContext.h +++ b/src/HttpContext.h @@ -159,9 +159,18 @@ private: httpResponseData->state |= HttpResponseData::HTTP_CONNECTION_CLOSE; } + /* Select the router based on SNI (only possible for SSL) */ + auto *selectedRouter = &httpContextData->router; + if constexpr (SSL) { + void *domainRouter = us_socket_server_name_userdata(SSL, (struct us_socket_t *) s); + if (domainRouter) { + selectedRouter = (decltype(selectedRouter)) domainRouter; + } + } + /* Route the method and URL */ - httpContextData->router.getUserData() = {(HttpResponse *) s, httpRequest}; - if (!httpContextData->router.route(httpRequest->getMethod(), httpRequest->getUrl())) { + selectedRouter->getUserData() = {(HttpResponse *) s, httpRequest}; + if (!selectedRouter->route(httpRequest->getMethod(), httpRequest->getUrl())) { /* We have to force close this socket as we have no handler for it */ us_socket_close(SSL, (us_socket_t *) s, 0, nullptr); return nullptr; @@ -406,12 +415,12 @@ public: /* Todo: This is ugly, fix */ std::vector methods; if (method == "*") { - methods = httpContextData->router.methods; + methods = httpContextData->currentRouter->methods; } else { methods = {method}; } - httpContextData->router.add(methods, pattern, [handler = std::move(handler)](auto *r) mutable { + httpContextData->currentRouter->add(methods, pattern, [handler = std::move(handler)](auto *r) mutable { auto user = r->getUserData(); user.httpRequest->setYield(false); user.httpRequest->setParameters(r->getParameters()); @@ -429,7 +438,7 @@ public: return false; } return true; - }, method == "*" ? httpContextData->router.LOW_PRIORITY : (upgrade ? httpContextData->router.HIGH_PRIORITY : httpContextData->router.MEDIUM_PRIORITY)); + }, method == "*" ? httpContextData->currentRouter->LOW_PRIORITY : (upgrade ? httpContextData->currentRouter->HIGH_PRIORITY : httpContextData->currentRouter->MEDIUM_PRIORITY)); } /* Listen to port using this HttpContext */ diff --git a/src/HttpContextData.h b/src/HttpContextData.h index 9375994..157af35 100644 --- a/src/HttpContextData.h +++ b/src/HttpContextData.h @@ -42,6 +42,10 @@ private: HttpRequest *httpRequest; }; + /* This is the currently browsed-to router when using SNI */ + HttpRouter *currentRouter = &router; + + /* This is the default router for default SNI or non-SSL */ HttpRouter router; void *upgradedWebSocket = nullptr; bool isParsingHttp = false; diff --git a/uSockets b/uSockets index 3f0b39e..d8967af 160000 --- a/uSockets +++ b/uSockets @@ -1 +1 @@ -Subproject commit 3f0b39ea94726ef04a75f7446150df98b834dfe7 +Subproject commit d8967af421983d40422094e31c54d9f1febeea49