Skip to content

Commit

Permalink
[cookie_manager] Fix set-cookie multi-value parsing (#1675)
Browse files Browse the repository at this point in the history
### New Pull Request Checklist

- [x] I have read the
[Documentation](https://pub.dev/documentation/dio/latest/)
- [x] I have searched for a similar pull request in the
[project](https://github.com/cfug/dio/pulls) and found none
- [x] I have updated this branch with the latest `main` branch to avoid
conflicts (via merge from master or rebase)
- [x] I have added the required tests to prove the fix/feature I'm
adding
- [ ] I have updated the documentation (if necessary)
- [x] I have run the tests without failures

### Additional context and info (if any)

Fix #1674
  • Loading branch information
Vovcharaa authored Feb 20, 2023
1 parent 17bdbb3 commit 2472b8b
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 3 deletions.
3 changes: 2 additions & 1 deletion plugins/cookie_manager/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# CHANGELOG

# 2.1.1
## 2.1.1

* Fix #1651
* Fix #1674

## 2.1.0

Expand Down
18 changes: 16 additions & 2 deletions plugins/cookie_manager/lib/src/cookie_mgr.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@ const _kIsWeb = bool.hasEnvironment('dart.library.js_util')
? bool.fromEnvironment('dart.library.js_util')
: identical(0, 0.0);

/// - `(?<=)` is a positive lookbehind assertion that matches a comma (",")
/// only if it's preceded by a specific pattern. In this case, the lookbehind
/// assertion is empty, which means it matches any comma that's preceded by any character.
/// - `(,)` captures the comma as a group.
/// - `(?=[^;]+?=)` is a positive lookahead assertion that matches a comma only
/// if it's followed by a specific pattern. In this case, it matches any comma
/// that's followed by one or more characters that are not semicolons (";") and
/// then an equals sign ("="). This ensures that the comma is not part of a cookie
/// attribute like "expires=Sun, 19 Feb 3000 01:43:15 GMT", which could also contain commas.
final _setCookieReg = RegExp('(?<=)(,)(?=[^;]+?=)');

/// Cookie manager for HTTP requests based on [CookieJar].
class CookieManager extends Interceptor {
const CookieManager(
Expand Down Expand Up @@ -70,9 +81,12 @@ class CookieManager extends Interceptor {
}

Future<void> _saveCookies(Response response) async {
final cookies = response.headers[HttpHeaders.setCookieHeader];
final setCookies = response.headers[HttpHeaders.setCookieHeader];

if (cookies != null) {
if (setCookies != null) {
final cookies = setCookies
.map((str) => str.split(_setCookieReg))
.expand((element) => element);
await cookieJar.saveFromResponse(
response.requestOptions.uri,
cookies.map((str) => Cookie.fromSetCookieValue(str)).toList(),
Expand Down
27 changes: 27 additions & 0 deletions plugins/cookie_manager/test/cookies_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,33 @@ void main() {
HttpHeaders.cookieHeader: mockSecondRequestCookies,
});

cookieManager.onRequest(options, mockRequestInterceptorHandler);
});
test('testing set-cookies parsing', () async {
const List<String> mockResponseCookies = [
'key=value; expires=Sun, 19 Feb 3000 00:42:14 GMT; path=/; HttpOnly; secure; SameSite=Lax',
'key1=value1; expires=Sun, 19 Feb 3000 01:43:15 GMT; path=/; HttpOnly; secure; SameSite=Lax, '
'key2=value2; expires=Sat, 20 May 3000 00:43:15 GMT; path=/; HttpOnly; secure; SameSite=Lax',
];
const exampleUrl = 'https://example.com';

final expectResult = 'key=value; key1=value1; key2=value2';

final cookieJar = CookieJar();
final cookieManager = CookieManager(cookieJar);
final mockRequestInterceptorHandler =
MockRequestInterceptorHandler(expectResult);
final mockResponseInterceptorHandler = MockResponseInterceptorHandler();
final requestOptions = RequestOptions(baseUrl: exampleUrl);

final mockResponse = Response(
requestOptions: requestOptions,
headers: Headers.fromMap(
{HttpHeaders.setCookieHeader: mockResponseCookies},
));
cookieManager.onResponse(mockResponse, mockResponseInterceptorHandler);
final options = RequestOptions(baseUrl: exampleUrl);

cookieManager.onRequest(options, mockRequestInterceptorHandler);
});
}

0 comments on commit 2472b8b

Please sign in to comment.