Skip to content
This repository has been archived by the owner on Feb 25, 2022. It is now read-only.

Commit

Permalink
fix #120: Parameters are not decoded when retrieved.
Browse files Browse the repository at this point in the history
  • Loading branch information
csells committed Nov 7, 2021
1 parent ce4a68d commit 02c6820
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 86 deletions.
10 changes: 5 additions & 5 deletions example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ packages:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.8.1"
version: "2.8.2"
boolean_selector:
dependency: transitive
description:
Expand All @@ -42,7 +42,7 @@ packages:
name: characters
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
version: "1.2.0"
charcode:
dependency: transitive
description:
Expand Down Expand Up @@ -113,7 +113,7 @@ packages:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.10"
version: "0.12.11"
meta:
dependency: transitive
description:
Expand Down Expand Up @@ -202,7 +202,7 @@ packages:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.2"
version: "0.4.3"
typed_data:
dependency: transitive
description:
Expand Down Expand Up @@ -258,7 +258,7 @@ packages:
name: vector_math
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "2.1.1"
sdks:
dart: ">=2.14.0 <3.0.0"
flutter: ">=2.0.0"
128 changes: 73 additions & 55 deletions lib/src/go_route_match.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,66 +13,24 @@ class GoRouteMatch {
required this.route,
required this.subloc,
required this.fullpath,
required this.params,
required this.encodedParams,
required this.queryParams,
required this.extra,
this.pageKey,
}) : assert(subloc.startsWith('/')),
assert(Uri.parse(subloc).queryParameters.isEmpty),
assert(fullpath.startsWith('/')),
assert(Uri.parse(fullpath).queryParameters.isEmpty);

/// The matched route.
final GoRoute route;

/// Matched sub-location.
final String subloc; // e.g. /family/f2

/// Matched full path.
final String fullpath; // e.g. /family/:fid

/// Parameters for the matched route.
final Map<String, String> params;

/// Query parameters for the matched route.
final Map<String, String> queryParams;

/// An extra object to pass along with the navigation.
final Object? extra;

/// Optional value key of type string, to hold a unique reference to a page.
final ValueKey<String>? pageKey;

// ignore: public_member_api_docs
static GoRouteMatch? match({
required GoRoute route,
required String restLoc, // e.g. person/p1
required String parentSubloc, // e.g. /family/f2
required String path, // e.g. person/:pid
required String fullpath, // e.g. /family/:fid/person/:pid
required Map<String, String> queryParams,
required Object? extra,
}) {
assert(!path.contains('//'));

final match = route.matchPatternAsPrefix(restLoc);
if (match == null) return null;

final params = route.extractPathParams(match);
final pathLoc = _locationFor(path, params);
final subloc = GoRouterDelegate.fullLocFor(parentSubloc, pathLoc);
return GoRouteMatch(
route: route,
subloc: subloc,
fullpath: fullpath,
params: params,
queryParams: queryParams,
extra: extra,
);
assert(Uri.parse(fullpath).queryParameters.isEmpty) {
if (kDebugMode) {
for (final p in encodedParams.entries) {
assert(p.value == Uri.encodeComponent(Uri.decodeComponent(p.value)),
'encodedParams[${p.key}] is not encoded properly: "${p.value}"');
}
}
}

// ignore: prefer_constructors_over_static_methods, public_member_api_docs
static GoRouteMatch matchNamed({
// ignore: public_member_api_docs
factory GoRouteMatch.matchNamed({
required GoRoute route,
required String name, // e.g. person
required String fullpath, // e.g. /family/:fid/person/:pid
Expand All @@ -99,20 +57,80 @@ class GoRouteMatch {
}
}

final subloc = _locationFor(fullpath, params);
final encodedParams = {
for (final param in params.entries)
param.key: Uri.encodeComponent(param.value)
};

final subloc = _locationFor(fullpath, encodedParams);
return GoRouteMatch(
route: route,
subloc: subloc,
fullpath: fullpath,
encodedParams: encodedParams,
queryParams: queryParams,
extra: extra,
);
}

// ignore: public_member_api_docs
static GoRouteMatch? match({
required GoRoute route,
required String restLoc, // e.g. person/p1
required String parentSubloc, // e.g. /family/f2
required String path, // e.g. person/:pid
required String fullpath, // e.g. /family/:fid/person/:pid
required Map<String, String> queryParams,
required Object? extra,
}) {
assert(!path.contains('//'));

final match = route.matchPatternAsPrefix(restLoc);
if (match == null) return null;

final encodedParams = route.extractPathParams(match);
final pathLoc = _locationFor(path, encodedParams);
final subloc = GoRouterDelegate.fullLocFor(parentSubloc, pathLoc);
return GoRouteMatch(
route: route,
subloc: subloc,
fullpath: fullpath,
params: params,
encodedParams: encodedParams,
queryParams: queryParams,
extra: extra,
);
}

/// The matched route.
final GoRoute route;

/// Matched sub-location.
final String subloc; // e.g. /family/f2

/// Matched full path.
final String fullpath; // e.g. /family/:fid

/// Parameters for the matched route, URI-encoded.
final Map<String, String> encodedParams;

/// Query parameters for the matched route.
final Map<String, String> queryParams;

/// An extra object to pass along with the navigation.
final Object? extra;

/// Optional value key of type string, to hold a unique reference to a page.
final ValueKey<String>? pageKey;

/// Parameters for the matched route, URI-decoded.
Map<String, String> get decodedParams => {
for (final param in encodedParams.entries)
param.key: Uri.decodeComponent(param.value)
};

/// for use by the Router architecture as part of the GoRouteMatch
@override
String toString() => 'GoRouteMatch($fullpath, $params)';
String toString() => 'GoRouteMatch($fullpath, $encodedParams)';

/// expand a path w/ param slots using params, e.g. family/:fid => family/f1
static String _locationFor(String path, Map<String, String> params) =>
Expand Down
21 changes: 9 additions & 12 deletions lib/src/go_router_delegate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ class GoRouterDelegate extends RouterDelegate<Uri>
route: route,
subloc: '/TBD',
fullpath: fullpath,
params: {},
encodedParams: {},
queryParams: {},
extra: null,
);
Expand Down Expand Up @@ -254,7 +254,7 @@ class GoRouterDelegate extends RouterDelegate<Uri>
route: top.route,
subloc: top.subloc,
fullpath: top.fullpath,
params: top.params,
encodedParams: top.encodedParams,
queryParams: top.queryParams,
extra: extra,
pageKey: pageKey,
Expand Down Expand Up @@ -332,7 +332,7 @@ class GoRouterDelegate extends RouterDelegate<Uri>
name: top.route.name,
path: top.route.path,
fullpath: top.fullpath,
params: top.params,
params: top.decodedParams,
queryParams: top.queryParams,
extra: extra,
),
Expand All @@ -355,7 +355,7 @@ class GoRouterDelegate extends RouterDelegate<Uri>
GoRouteMatch(
subloc: uri.path,
fullpath: uri.path,
params: {},
encodedParams: {},
queryParams: uri.queryParameters,
extra: null,
route: GoRoute(
Expand Down Expand Up @@ -418,7 +418,8 @@ class GoRouterDelegate extends RouterDelegate<Uri>
assert(matchStacks.length == 1);
final match = matchStacks.first.last;
final loc1 = _addQueryParams(match.subloc, match.queryParams);
final loc2 = _canonicalUri(location);
final uri2 = Uri.parse(location);
final loc2 = _addQueryParams(uri2.path, uri2.queryParameters);

// NOTE: match the lower case, since subloc is canonicalized to match the
// path case whereas the location can be any case
Expand Down Expand Up @@ -659,7 +660,7 @@ class GoRouterDelegate extends RouterDelegate<Uri>
for (final match in matches) {
// merge new params to keep params from previously matched paths, e.g.
// /family/:fid/person/:pid provides fid and pid to person/:pid
params = {...params, ...match.params};
params = {...params, ...match.encodedParams};

// get a page from the builder and associate it with a sub-location
yield match.route.pageBuilder(
Expand Down Expand Up @@ -707,13 +708,9 @@ class GoRouterDelegate extends RouterDelegate<Uri>
}
}

// e.g. %20 => +
static String _canonicalUri(String loc) {
final uri = Uri.parse(loc);
final canon = Uri.decodeFull(
Uri(path: uri.path, queryParameters: uri.queryParameters).toString(),
);
return canon.endsWith('?') ? canon.substring(0, canon.length - 1) : canon;
final canon = Uri.parse(loc).toString();
return canon.endsWith('?') ? canon.substring(0, canon.length - 1) : canon;
}

static String _addQueryParams(String loc, Map<String, String> queryParams) {
Expand Down
10 changes: 5 additions & 5 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ packages:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.8.1"
version: "2.8.2"
boolean_selector:
dependency: transitive
description:
Expand All @@ -28,7 +28,7 @@ packages:
name: characters
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
version: "1.2.0"
charcode:
dependency: transitive
description:
Expand Down Expand Up @@ -85,7 +85,7 @@ packages:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.10"
version: "0.12.11"
meta:
dependency: transitive
description:
Expand Down Expand Up @@ -153,7 +153,7 @@ packages:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.2"
version: "0.4.3"
typed_data:
dependency: transitive
description:
Expand All @@ -167,7 +167,7 @@ packages:
name: vector_math
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "2.1.1"
sdks:
dart: ">=2.14.0 <3.0.0"
flutter: ">=1.17.0"
18 changes: 9 additions & 9 deletions test/go_router_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -632,13 +632,13 @@ void main() {

final router = _router(routes);
final loc = router.namedLocation('page1', params: {'param1': param1});
print('loc= $loc');
dump('loc= $loc');
router.go(loc);

final matches = router.routerDelegate.matches;
print('param1= ${matches[0].params['param1']}');
dump('param1= ${matches[0].decodedParams['param1']}');
expect(router.pageFor(matches[0]).runtimeType, DummyPage);
expect(matches[0].params['param1'], param1);
expect(matches[0].decodedParams['param1'], param1);
});

test('preserve query param spaces and slashes', () {
Expand All @@ -650,11 +650,11 @@ void main() {
final router = _router(routes);
final loc =
router.namedLocation('page1', queryParams: {'param1': param1});
print('loc= $loc');
dump('loc= $loc');
router.go(loc);

final matches = router.routerDelegate.matches;
print('param1= ${matches[0].queryParams['param1']}');
dump('param1= ${matches[0].queryParams['param1']}');
expect(router.pageFor(matches[0]).runtimeType, DummyPage);
expect(matches[0].queryParams['param1'], param1);
});
Expand Down Expand Up @@ -1041,7 +1041,7 @@ void main() {
expect(router.location, loc);
expect(matches.length, 1);
expect(router.pageFor(matches[0]).runtimeType, FamilyPage);
expect(matches[0].params['fid'], fid);
expect(matches[0].decodedParams['fid'], fid);
}
});

Expand Down Expand Up @@ -1079,13 +1079,13 @@ void main() {
];

final router = _router(routes);
final loc = '/page1/${Uri.encodeQueryComponent(param1)}';
final loc = '/page1/${Uri.encodeComponent(param1)}';
router.go(loc);

final matches = router.routerDelegate.matches;
print('param1= ${matches[0].params['param1']}');
dump('param1= ${matches[0].decodedParams['param1']}');
expect(router.pageFor(matches[0]).runtimeType, DummyPage);
expect(matches[0].params['param1'], param1);
expect(matches[0].decodedParams['param1'], param1);
});

test('preserve query param spaces and slashes', () {
Expand Down

0 comments on commit 02c6820

Please sign in to comment.