@@ -19,7 +19,7 @@ import 'package:http_methods/http_methods.dart';
1919import 'package:meta/meta.dart' show sealed;
2020import 'package:shelf/shelf.dart' ;
2121
22- import 'router_entry.dart' show ParamInfo, RouterEntry;
22+ import 'router_entry.dart' show RouterEntry;
2323
2424/// Get a URL parameter captured by the [Router] .
2525@Deprecated ('Use Request.params instead' )
@@ -113,6 +113,12 @@ class Router {
113113 final List <RouterEntry > _routes = [];
114114 final Handler _notFoundHandler;
115115
116+ /// Name of the parameter used for matching the rest of te path in a mounted
117+ /// route.
118+ /// Prefixed with two underscores to avoid conflicts
119+ /// with user defined path parameters
120+ static const _kRestPathParam = '__path' ;
121+
116122 /// Creates a new [Router] routing requests to handlers.
117123 ///
118124 /// The [notFoundHandler] will be invoked for requests where no matching route
@@ -156,100 +162,60 @@ class Router {
156162 }
157163
158164 // first slash is always in request.handlerPath
159- final path = prefix.substring (1 );
160-
161- // Prefix it with two underscores to avoid conflicts
162- // with user defined path parameters
163- const pathParam = '__path' ;
165+ const restPathParam = _kRestPathParam;
164166
165167 if (prefix.endsWith ('/' )) {
166168 _all (
167- prefix + '<$pathParam |[^]*>' ,
169+ prefix + '<$restPathParam |[^]*>' ,
168170 (Request request, RouterEntry route) {
169171 // Remove path param from extracted route params
170- final paramsList = [...route.paramInfos ]..removeLast ();
171- return _invokeMountedHandler (request, handler, path, paramsList);
172+ final paramsList = [...route.params ]..removeLast ();
173+ return _invokeMountedHandler (request, handler, paramsList);
172174 },
173175 mounted: true ,
174176 );
175177 } else {
176178 _all (
177179 prefix,
178180 (Request request, RouterEntry route) {
179- return _invokeMountedHandler (
180- request, handler, path, route.paramInfos);
181+ return _invokeMountedHandler (request, handler, route.params);
181182 },
182183 mounted: true ,
183184 );
184185 _all (
185- prefix + '/<$pathParam |[^]*>' ,
186+ prefix + '/<$restPathParam |[^]*>' ,
186187 (Request request, RouterEntry route) {
187188 // Remove path param from extracted route params
188- final paramsList = [...route.paramInfos]..removeLast ();
189- return _invokeMountedHandler (
190- request, handler, path + '/' , paramsList);
189+ final paramsList = [...route.params]..removeLast ();
190+ return _invokeMountedHandler (request, handler, paramsList);
191191 },
192192 mounted: true ,
193193 );
194194 }
195195 }
196196
197- Future <Response > _invokeMountedHandler (Request request, Function handler,
198- String path, List <ParamInfo > paramInfos) async {
199- final params = _getParamsFromRequest (request);
200- final resolvedPath =
201- _replaceParamsInPath (request, path, params, paramInfos);
197+ Future <Response > _invokeMountedHandler (
198+ Request request, Function handler, List <String > pathParams) async {
199+ final paramsMap = request.params;
200+
201+ final pathParamSegment = paramsMap[_kRestPathParam];
202+ final urlPath = request.url.path;
203+ late final String effectivePath;
204+ if (pathParamSegment != null && pathParamSegment.isNotEmpty) {
205+ /// If we encounter the "rest path" parameter we remove it
206+ /// from the request path that shelf will handle.
207+ effectivePath =
208+ urlPath.substring (0 , urlPath.length - pathParamSegment.length);
209+ } else {
210+ effectivePath = urlPath;
211+ }
202212
203213 return await Function .apply (handler, [
204- request.change (path: resolvedPath ),
205- ...paramInfos .map ((info ) => params[info.name ]),
214+ request.change (path: effectivePath ),
215+ ...pathParams .map ((param ) => paramsMap[param ]),
206216 ]) as Response ;
207217 }
208218
209- Map <String , String > _getParamsFromRequest (Request request) {
210- return request.context['shelf_router/params' ] as Map <String , String >;
211- }
212-
213- /// Replaces the variable slots (<someVar>) from [path] with the
214- /// values from [params]
215- String _replaceParamsInPath (
216- Request request,
217- String path,
218- Map <String , String > params,
219- List <ParamInfo > paramInfos,
220- ) {
221- // we iterate the non-resolved path and we write to a StringBuffer
222- // resolving ther parameters along the way
223- final resolvedPathBuff = StringBuffer ();
224- var paramIndex = 0 ;
225- var charIndex = 0 ;
226- while (charIndex < path.length) {
227- if (paramIndex < paramInfos.length) {
228- final paramInfo = paramInfos[paramIndex];
229- if (charIndex < paramInfo.startIdx - 1 ) {
230- // Add up until the param slot starts
231- final part = path.substring (charIndex, paramInfo.startIdx - 1 );
232- resolvedPathBuff.write (part);
233- charIndex += part.length;
234- } else {
235- // Add the resolved value of the parameter
236- final paramName = paramInfo.name;
237- final paramValue = params[paramName]! ;
238- resolvedPathBuff.write (paramValue);
239- charIndex = paramInfo.endIdx - 1 ;
240- paramIndex++ ;
241- }
242- } else {
243- // All params looped, so add up until the end of the path
244- final part = path.substring (charIndex, path.length);
245- resolvedPathBuff.write (part);
246- charIndex += part.length;
247- }
248- }
249- var resolvedPath = resolvedPathBuff.toString ();
250- return resolvedPath;
251- }
252-
253219 /// Route incoming requests to registered handlers.
254220 ///
255221 /// This method allows a Router instance to be a [Handler] .
0 commit comments