Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions lib/src/file_storage.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,9 @@ class FileStorage implements Storage {
/// A storage can be used across different jars, so this cannot be final.
late String _currentDirectory;

/// {@nodoc}
@visibleForTesting
final bool shouldCreateDirectory;

/// {@nodoc}
@visibleForTesting
String get currentDirectory => _currentDirectory;

Expand Down
36 changes: 23 additions & 13 deletions lib/src/jar/persist.dart
Original file line number Diff line number Diff line change
Expand Up @@ -126,23 +126,33 @@ class PersistCookieJar extends DefaultCookieJar {
) {
return domain.cast<String, Map<String, dynamic>>().map(
(path, cookies) {
final result = cookies.cast<String, SerializableCookie>().map(
(key, cookie) {
final isSession =
cookie.cookie.expires == null && cookie.cookie.maxAge == null;
if ((isSession && persistSession) ||
(persistSession && !cookie.isExpired())) {
return MapEntry(key, cookie);
} else {
return MapEntry(null, cookie);
}
},
)..removeWhere((k, v) => k == null);
return MapEntry(path, result.cast<String, SerializableCookie>());
return MapEntry(
path,
Map.fromEntries(
_filterPathEntries(
cookies.cast<String, SerializableCookie>(),
),
),
);
},
);
}

Iterable<MapEntry<String, SerializableCookie>> _filterPathEntries(
Map<String, SerializableCookie> cookies,
) sync* {
for (final entry in cookies.entries) {
final cookie = entry.value;

final isSession =
cookie.cookie.expires == null && cookie.cookie.maxAge == null;
if (isSession && !persistSession) continue;
if (cookie.isExpired()) continue;

yield entry;
}
}

/// Delete cookies for specified [uri].
/// This API will delete all cookies for the `uri.host`, it will ignored the `uri.path`.
///
Expand Down
112 changes: 112 additions & 0 deletions test/cookie_jar_test.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
@TestOn('vm')
library cookie_jar_test;

import 'dart:async';
import 'dart:convert';
import 'dart:io';
Expand Down Expand Up @@ -273,6 +275,116 @@ void main() async {
expect(otherResults, isEmpty);
});

group('Test session cookies persistance', () {
test('PersistCookieJar persists session cookies by default', () async {
final uri = Uri.parse('https://session-default-test.com/');

// Create session cookies (no expires or maxAge)
final sessionCookies = <Cookie>[
Cookie('session_cookie', 'session_value'),
Cookie('another_session', 'another_value'),
];

// Create non-session cookies (with expires)
final persistentCookies = <Cookie>[
Cookie('persistent_cookie', 'persistent_value')
..expires = DateTime.now().add(const Duration(days: 1)),
];

// Mix of session and persistent cookies
final mixedCookies = <Cookie>[
...sessionCookies,
...persistentCookies,
];

// Test with default persistSession (should be true)
PersistCookieJar cj = PersistCookieJar(
storage: FileStorage('./test/cookies/session_default_test'),
);

await cj.delete(uri);
await cj.saveFromResponse(uri, mixedCookies);

// Create a new instance to verify persistence
cj = PersistCookieJar(
storage: FileStorage('./test/cookies/session_default_test'),
);

final results = await cj.loadForRequest(uri);

// All cookies (session and persistent) should be loaded
expect(results.length, 3);

// Verify all cookies are present
expect(results.any((c) => c.name == 'session_cookie'), true);
expect(results.any((c) => c.name == 'another_session'), true);
expect(results.any((c) => c.name == 'persistent_cookie'), true);

// Verify values
final sessionCookie =
results.firstWhere((c) => c.name == 'session_cookie');
expect(sessionCookie.value, 'session_value');

final anotherSession =
results.firstWhere((c) => c.name == 'another_session');
expect(anotherSession.value, 'another_value');

final persistentCookie =
results.firstWhere((c) => c.name == 'persistent_cookie');
expect(persistentCookie.value, 'persistent_value');
});

test(
'PersistCookieJar does not persist session cookies when `persistSession` is false',
() async {
final uri = Uri.parse('https://session-test.com/');

// Create session cookies (no expires or maxAge)
final sessionCookies = <Cookie>[
Cookie('session_cookie', 'session_value'),
Cookie('another_session', 'another_value'),
];

// Create non-session cookies (with expires)
final persistentCookies = <Cookie>[
Cookie('persistent_cookie', 'persistent_value')
..expires = DateTime.now().add(const Duration(days: 1)),
];

// Mix of session and persistent cookies
final mixedCookies = <Cookie>[
...sessionCookies,
...persistentCookies,
];

// Test with persistSession = false
PersistCookieJar cj = PersistCookieJar(
persistSession: false,
storage: FileStorage('./test/cookies/session_test'),
);

await cj.delete(uri);
await cj.saveFromResponse(uri, mixedCookies);

// Create a new instance to verify persistence
cj = PersistCookieJar(
persistSession: false,
storage: FileStorage('./test/cookies/session_test'),
);

final results = await cj.loadForRequest(uri);

// Only persistent cookies should be loaded
expect(results.length, 1);
expect(results[0].name, 'persistent_cookie');
expect(results[0].value, 'persistent_value');

// Verify session cookies are not present
expect(results.any((c) => c.name == 'session_cookie'), false);
expect(results.any((c) => c.name == 'another_session'), false);
});
});

group('FileStorage', () {
test('Parsed directory correctly', () async {
final s1 = FileStorage.test('./test/cookies');
Expand Down
2 changes: 2 additions & 0 deletions test/web_test.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
@TestOn('chrome')
library cookie_jar_web_test;

import 'package:cookie_jar/cookie_jar.dart';
import 'package:test/test.dart';

Expand Down