diff --git a/lib/src/file_storage.dart b/lib/src/file_storage.dart index 94aa0a7..121531f 100644 --- a/lib/src/file_storage.dart +++ b/lib/src/file_storage.dart @@ -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; diff --git a/lib/src/jar/persist.dart b/lib/src/jar/persist.dart index 71bba99..8c1ab13 100644 --- a/lib/src/jar/persist.dart +++ b/lib/src/jar/persist.dart @@ -126,23 +126,33 @@ class PersistCookieJar extends DefaultCookieJar { ) { return domain.cast>().map( (path, cookies) { - final result = cookies.cast().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()); + return MapEntry( + path, + Map.fromEntries( + _filterPathEntries( + cookies.cast(), + ), + ), + ); }, ); } + Iterable> _filterPathEntries( + Map 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`. /// diff --git a/test/cookie_jar_test.dart b/test/cookie_jar_test.dart index 1022685..40d7bd9 100644 --- a/test/cookie_jar_test.dart +++ b/test/cookie_jar_test.dart @@ -1,4 +1,6 @@ @TestOn('vm') +library cookie_jar_test; + import 'dart:async'; import 'dart:convert'; import 'dart:io'; @@ -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('session_cookie', 'session_value'), + Cookie('another_session', 'another_value'), + ]; + + // Create non-session cookies (with expires) + final persistentCookies = [ + Cookie('persistent_cookie', 'persistent_value') + ..expires = DateTime.now().add(const Duration(days: 1)), + ]; + + // Mix of session and persistent cookies + final mixedCookies = [ + ...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('session_cookie', 'session_value'), + Cookie('another_session', 'another_value'), + ]; + + // Create non-session cookies (with expires) + final persistentCookies = [ + Cookie('persistent_cookie', 'persistent_value') + ..expires = DateTime.now().add(const Duration(days: 1)), + ]; + + // Mix of session and persistent cookies + final mixedCookies = [ + ...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'); diff --git a/test/web_test.dart b/test/web_test.dart index 0795a94..0b43463 100644 --- a/test/web_test.dart +++ b/test/web_test.dart @@ -1,4 +1,6 @@ @TestOn('chrome') +library cookie_jar_web_test; + import 'package:cookie_jar/cookie_jar.dart'; import 'package:test/test.dart';