read method
Reads an existing session or creates a new one if it does not exist.
This method retrieves a session associated with the given request and
session name. If a session exists, it's loaded; otherwise, a new session
is created.
The request object provides context, including cookies or headers used to
identify the session. The name parameter uniquely identifies the session.
Returns a Future<Session> that completes with the loaded or newly created
Session object.
Example:
final session = await store.read(request, 'my_session');
Implementation
@override
Future<Session> read(Request request, String name) async {
Cookie cookie = request.cookies.firstWhere(
(c) => c.name == name,
orElse: () => Cookie(name, ''),
);
if (cookie.value.isEmpty) {
final header = request.header(HttpHeaders.cookieHeader);
if (header.isNotEmpty) {
for (final entry in header.split(';')) {
final trimmed = entry.trim();
if (trimmed.isEmpty) continue;
final separatorIndex = trimmed.indexOf('=');
if (separatorIndex == -1) continue;
final cookieName = trimmed.substring(0, separatorIndex).trim();
if (cookieName != name) continue;
final cookieValue = trimmed.substring(separatorIndex + 1).trim();
if (cookieValue.isEmpty) continue;
cookie = Cookie(cookieName, cookieValue);
break;
}
}
}
if (cookie.value.isEmpty) {
return Session(name: name, options: defaultOptions);
}
var value = cookie.value;
try {
value = Uri.decodeComponent(value);
} catch (_) {
// Value was not URI-encoded; continue with original payload for legacy cookies.
}
// Unwind the codec chain in the same order it was applied during encoding.
for (final codec in _decodeCodecs) {
try {
final decoded = codec.decode(name, value);
// The encoding step stores the next payload under the `"data"` key.
if (decoded.containsKey('data') && decoded['data'] is String) {
value = decoded['data'] as String;
} else {
// Fallback for single-codec or legacy payloads.
value = jsonEncode(decoded);
}
} catch (e) {
// Try the next codec in the chain
continue;
}
}
try {
final Map<String, dynamic> data =
jsonDecode(value) as Map<String, dynamic>;
final session = Session(
name: name,
options: defaultOptions,
id: data['id'] as String?,
values: Map<String, dynamic>.from(data['values'] as Map),
createdAt: DateTime.parse(data['created_at'] as String),
lastAccessed: DateTime.parse(data['last_accessed'] as String),
);
if (data['is_new'] != null) session.isNew = data['is_new'] as bool;
if (data['destroyed'] == true) session.destroy();
return session;
} catch (e) {
return Session(name: name, options: defaultOptions);
}
}