From bfcef430af6290374108111afabb211174ba962f Mon Sep 17 00:00:00 2001 From: Javad Zobeidi Date: Wed, 29 May 2024 18:56:50 +0330 Subject: [PATCH 1/2] Add domain to the router Fix static path issue url encode --- lib/src/route/route_data.dart | 2 +- lib/src/route/route_handler.dart | 47 ++++++++++++++++++++++++++++-- lib/src/route/router.dart | 24 +++++++++++++-- lib/src/route/set_static_path.dart | 5 ++-- test/unit/route_test.dart | 9 +++++- 5 files changed, 78 insertions(+), 9 deletions(-) diff --git a/lib/src/route/route_data.dart b/lib/src/route/route_data.dart index bd15857..d874e28 100644 --- a/lib/src/route/route_data.dart +++ b/lib/src/route/route_data.dart @@ -6,7 +6,7 @@ class RouteData { final dynamic action; Map? params; List preMiddleware; - final String? domain; + String? domain; final bool? corsEnabled; final String? prefix; diff --git a/lib/src/route/route_handler.dart b/lib/src/route/route_handler.dart index 3cb81ae..381548b 100644 --- a/lib/src/route/route_handler.dart +++ b/lib/src/route/route_handler.dart @@ -9,7 +9,7 @@ import 'package:vania/src/utils/functions.dart'; Future httpRouteHandler(HttpRequest req) async { final route = _getMatchRoute( - req.uri.path.toLowerCase(), + Uri.decodeComponent(req.uri.path.toLowerCase()), req.method, req.headers.value(HttpHeaders.hostHeader), ); @@ -32,12 +32,47 @@ Future httpRouteHandler(HttpRequest req) async { return route; } +/// Exctract the domain from the url +String _exctractDomain(String domain, String path) { + String firstPart = domain.split('.').first.toLowerCase(); + final RegExp domainRegex = RegExp(r'\{[^}]*\}'); + bool containsPlaceholder = domainRegex.hasMatch(path); + String domainUri = domain; + if (containsPlaceholder) { + domainUri = path.replaceAll(domainRegex, firstPart).toLowerCase(); + } + return domainUri; +} + + +/// Exctarct username from {username} +/// Or any string between {} +String? _extractDomainPlaceholder(String input) { + final RegExp regex = RegExp(r'\{([^}]*)\}'); + final match = regex.firstMatch(input); + if (match != null) { + return match.group(1)!; + } else { + return null; + } +} + RouteData? _getMatchRoute(String inputRoute, String method, String? domain) { + String? domainParameter; + String? domainPlaceholder; List methodMatchedRoutes = Router().routes.where((RouteData route) { if (domain != null && route.domain != null) { + String subDomain = _exctractDomain( + domain, + route.domain!, + ); + + domainPlaceholder = _extractDomainPlaceholder(route.domain!); + domainParameter = subDomain.split('.').first.toLowerCase(); + return route.method.toLowerCase() == method.toLowerCase() && - route.domain?.toLowerCase() == domain.toLowerCase(); + subDomain == domain.toLowerCase(); } else { return route.method.toLowerCase() == method.toLowerCase(); } @@ -55,7 +90,7 @@ RouteData? _getMatchRoute(String inputRoute, String method, String? domain) { /// When route is the same route exactly same route. /// route without params, eg. /api/example - if (routePath == inputRoute.trim()) { + if (routePath == inputRoute.trim() && route.domain == null) { matchRoute = route; break; } @@ -63,10 +98,16 @@ RouteData? _getMatchRoute(String inputRoute, String method, String? domain) { /// when route have params /// eg. /api/admin/{adminId} Iterable parameterNames = _getParameterNameFromRoute(route); + Iterable matches = _getPatternMatches(inputRoute, routePath); if (matches.isNotEmpty) { matchRoute = route; matchRoute.params = _getParameterAsMap(matches, parameterNames); + if (domainPlaceholder != null && domainParameter != null) { + matchRoute.params?.addAll({ + domainPlaceholder!: domainParameter, + }); + } break; } } diff --git a/lib/src/route/router.dart b/lib/src/route/router.dart index bbcb9ad..d85d444 100644 --- a/lib/src/route/router.dart +++ b/lib/src/route/router.dart @@ -10,6 +10,7 @@ class Router { String? _prefix; String? _groupPrefix; + String? _groupDomain; List? _groupMiddleware; static basePrefix(String prefix) { @@ -27,6 +28,7 @@ class Router { return Router() ._addRoute(HttpRequestMethod.get, path, action) .middleware(Router()._groupMiddleware) + .domain(Router()._groupDomain) .prefix(Router()._groupPrefix); } @@ -34,6 +36,7 @@ class Router { return Router() ._addRoute(HttpRequestMethod.post, path, action) .middleware(Router()._groupMiddleware) + .domain(Router()._groupDomain) .prefix(Router()._groupPrefix); } @@ -41,6 +44,7 @@ class Router { return Router() ._addRoute(HttpRequestMethod.put, path, action) .middleware(Router()._groupMiddleware) + .domain(Router()._groupDomain) .prefix(Router()._groupPrefix); } @@ -48,6 +52,7 @@ class Router { return Router() ._addRoute(HttpRequestMethod.patch, path, action) .middleware(Router()._groupMiddleware) + .domain(Router()._groupDomain) .prefix(Router()._groupPrefix); } @@ -55,6 +60,7 @@ class Router { return Router() ._addRoute(HttpRequestMethod.delete, path, action) .middleware(Router()._groupMiddleware) + .domain(Router()._groupDomain) .prefix(Router()._groupPrefix); } @@ -62,6 +68,7 @@ class Router { return Router() ._addRoute(HttpRequestMethod.options, path, action) .middleware(Router()._groupMiddleware) + .domain(Router()._groupDomain) .prefix(Router()._prefix); } @@ -91,6 +98,13 @@ class Router { return this; } + Router domain([String? domain]) { + if (domain != null) { + _routes.last.domain = domain; + } + return this; + } + static void websocket( String path, Function(WebSocketEvent) eventCallBack, { @@ -102,12 +116,18 @@ class Router { )); } - static void group(Function callBack, - {String? prefix, List? middleware}) { + static void group( + Function callBack, { + String? prefix, + List? middleware, + String? domain, + }) { Router()._groupPrefix = prefix; Router()._groupMiddleware = middleware; + Router()._groupDomain = domain; callBack(); Router()._groupPrefix = null; Router()._groupMiddleware = null; + Router()._groupDomain = null; } } diff --git a/lib/src/route/set_static_path.dart b/lib/src/route/set_static_path.dart index c059a8c..82f4f89 100644 --- a/lib/src/route/set_static_path.dart +++ b/lib/src/route/set_static_path.dart @@ -4,8 +4,9 @@ import 'package:vania/src/utils/functions.dart'; import 'package:vania/vania.dart'; Future setStaticPath(HttpRequest req) { - if (!req.uri.path.endsWith("/")) { - File file = File(sanitizeRoutePath("public/${req.uri.path}")); + String path = Uri.decodeComponent(req.uri.path); + if (!path.endsWith("/")) { + File file = File(sanitizeRoutePath("public/$path")); if (file.existsSync()) { Response response = Response.file(file.path); response.makeResponse(req.response); diff --git a/test/unit/route_test.dart b/test/unit/route_test.dart index c300850..196d29b 100644 --- a/test/unit/route_test.dart +++ b/test/unit/route_test.dart @@ -21,7 +21,7 @@ void main() { expect(data.path, '/post'); expect(data.method, 'post'); }); - + test('delete route', () { Router.delete('/delete', () {}); RouteData data = Router().routes.first; @@ -49,6 +49,13 @@ void main() { expect(data.path, '/options'); expect(data.method, 'options'); }); + + test('domain route', () { + Router.get('/get-with-domain', () {}).domain('{username}.test.com'); + RouteData data = Router().routes.first; + expect(data.domain, '{username}.test.com'); + expect(data.method, 'get'); + }); test('group route test', () { Router.group(() { From 2fc8d86a77b140bee2794b9a2b99ce51f34721fc Mon Sep 17 00:00:00 2001 From: Javad Zobeidi Date: Wed, 29 May 2024 18:58:25 +0330 Subject: [PATCH 2/2] Dart format --- lib/src/route/route_handler.dart | 1 - test/unit/route_test.dart | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/src/route/route_handler.dart b/lib/src/route/route_handler.dart index 381548b..b8a8600 100644 --- a/lib/src/route/route_handler.dart +++ b/lib/src/route/route_handler.dart @@ -44,7 +44,6 @@ String _exctractDomain(String domain, String path) { return domainUri; } - /// Exctarct username from {username} /// Or any string between {} String? _extractDomainPlaceholder(String input) { diff --git a/test/unit/route_test.dart b/test/unit/route_test.dart index 196d29b..eb93b72 100644 --- a/test/unit/route_test.dart +++ b/test/unit/route_test.dart @@ -21,7 +21,7 @@ void main() { expect(data.path, '/post'); expect(data.method, 'post'); }); - + test('delete route', () { Router.delete('/delete', () {}); RouteData data = Router().routes.first; @@ -49,7 +49,7 @@ void main() { expect(data.path, '/options'); expect(data.method, 'options'); }); - + test('domain route', () { Router.get('/get-with-domain', () {}).domain('{username}.test.com'); RouteData data = Router().routes.first;