fix(cookie_manager): deduplicate cookies when request is retried#2498
fix(cookie_manager): deduplicate cookies when request is retried#2498ersanKolay wants to merge 6 commits intocfug:mainfrom
Conversation
When a request is retried with the same RequestOptions, loadCookies merges previousCookies from headers with savedCookies from the jar without deduplication, causing cookies to accumulate on each retry. Filter out previousCookies that already exist in savedCookies by name, so jar cookies take precedence and no duplicates are produced. Closes cfug#2442
|
Is it possible to deduplicate cookies by checking their equality instead of rely on their name only? Will that (and current) consent any RFCs? |
|
I've check further with RFC 6265, which declared:
The current deduplicate behavior doesn't seem to be aligned, correct? |
Use (name, domain, path) identity per RFC 6265 Section 5.3 for cookie deduplication. Cookies parsed from the Cookie header lack domain/path metadata, so those fall back to name-only matching against saved cookies which are already URI-scoped by cookieJar.loadForRequest.
|
Good catch, thanks for referencing RFC 6265 Section 5.3. I've updated the deduplication to use One practical note: cookies parsed from the For cookies that do carry full metadata (domain and path set), the deduplication uses the full |
…aths Verifies that cookies with the same name but different paths (per RFC 6265 Section 5.3 identity) are both preserved and not incorrectly deduplicated on retry.
Minimal reproductionimport 'dart:io';
import 'package:cookie_jar/cookie_jar.dart';
import 'package:dio/dio.dart';
import 'package:dio_cookie_manager/dio_cookie_manager.dart';
void main() async {
final cookieJar = CookieJar();
final dio = Dio()..interceptors.add(CookieManager(cookieJar));
// Server sets two cookies
await cookieJar.saveFromResponse(
Uri.parse('https://example.com'),
[
Cookie('a', '1')..path = '/',
Cookie('b', '2')..path = '/',
],
);
// Simulate what happens on retry:
// CookieManager.onRequest runs twice on the same RequestOptions.
final options = RequestOptions(baseUrl: 'https://example.com');
final mgr = CookieManager(cookieJar);
// First run: sets Cookie header to "a=1; b=2"
final cookies1 = await mgr.loadCookies(options);
options.headers[HttpHeaders.cookieHeader] = cookies1;
print('1st: $cookies1');
// → a=1; b=2
// Second run (retry): header already has "a=1; b=2"
final cookies2 = await mgr.loadCookies(options);
print('2nd: $cookies2');
// Before fix: a=1; b=2; a=1; b=2 (duplicates!)
// After fix: a=1; b=2 ✓
// RFC 6265 case: same name, different paths — both preserved
final jar2 = CookieJar();
await jar2.saveFromResponse(
Uri.parse('https://example.com/api/endpoint'),
[
Cookie('session', 'abc')..path = '/',
Cookie('session', 'xyz')..path = '/api',
],
);
final mgr2 = CookieManager(jar2);
final opts2 = RequestOptions(baseUrl: 'https://example.com/api/endpoint');
final cookies3 = await mgr2.loadCookies(opts2);
print('RFC 6265: $cookies3');
// → session=xyz; session=abc (both kept, different paths)
} |
|
Looks like the coverage is dropping. |
Removed unreachable domain/path branch — per RFC 6265 Section 4.2, the Cookie header only carries name=value pairs without domain or path metadata. Name-only matching is sufficient since saved cookies are already URI-scoped by cookieJar.loadForRequest. Extracted the previous-cookie filtering into a named variable for better readability.
|
Updated — simplified the dedup logic and improved readability:
|
Code Coverage Report: Only Changed Files listed
Minimum allowed coverage is |
Summary
Fixes #2442.
When a request is retried (e.g. after token refresh),
loadCookiesmergespreviousCookiesfrom the existing header withsavedCookiesfrom the cookie jar without checking for duplicates. This causes cookies to accumulate on each retry attempt:The fix filters out
previousCookiesentries whose names already exist insavedCookies, so jar cookies take precedence and no duplicates are produced.The deduplication is done in
loadCookiesrather thangetCookiesto preserve the existing RFC 6265 behavior where same-name cookies with different paths are valid.Test plan
no duplicate cookies on retrytest that simulates the retry scenariodart formatanddart analyzeclean