Skip to content

Commit db114fa

Browse files
committed
fix: serve _navigateToUrl also uses root domain matching
Prevents re-navigation loops when login URLs (e.g. passport.csdn.net) redirect to main site (csdn.net) after auth. The serve command's _navigateToUrl now matches tabs by root domain and skips navigation when a same-root-domain tab already exists.
1 parent d23a56e commit db114fa

File tree

1 file changed

+38
-6
lines changed

1 file changed

+38
-6
lines changed

lib/src/cli/serve.dart

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -229,25 +229,57 @@ Future<void> _navigateToUrl(CdpDriver cdp, String url, int cdpPort) async {
229229
final tabs = (jsonDecode(body) as List).cast<Map<String, dynamic>>();
230230
client.close();
231231

232-
// Find tab with matching origin
233-
final matchingTab = tabs.cast<Map<String, dynamic>?>().firstWhere(
232+
// Find tab with matching origin or same root domain
233+
final targetHost = targetUri.host;
234+
final targetParts = targetHost.split('.');
235+
final targetRoot = targetParts.length >= 2
236+
? targetParts.sublist(targetParts.length - 2).join('.')
237+
: targetHost;
238+
239+
Map<String, dynamic>? matchingTab;
240+
bool isRootDomainMatch = false;
241+
242+
// 1. Exact origin match
243+
matchingTab = tabs.cast<Map<String, dynamic>?>().firstWhere(
234244
(t) => t!['type'] == 'page' && (t['url'] as String? ?? '').startsWith(targetOrigin),
235245
orElse: () => null,
236246
);
237247

248+
// 2. Root domain match (e.g. passport.csdn.net → www.csdn.net)
249+
if (matchingTab == null) {
250+
matchingTab = tabs.cast<Map<String, dynamic>?>().firstWhere(
251+
(t) {
252+
if (t!['type'] != 'page') return false;
253+
final tabHost = Uri.tryParse(t['url']?.toString() ?? '')?.host ?? '';
254+
final tabParts = tabHost.split('.');
255+
final tabRoot = tabParts.length >= 2
256+
? tabParts.sublist(tabParts.length - 2).join('.')
257+
: tabHost;
258+
return tabRoot == targetRoot && tabRoot.isNotEmpty;
259+
},
260+
orElse: () => null,
261+
);
262+
if (matchingTab != null) isRootDomainMatch = true;
263+
}
264+
238265
if (matchingTab != null) {
239-
// Connect to existing tab with same origin
266+
// Connect to existing tab with same origin/domain
240267
final wsUrl = matchingTab['webSocketDebuggerUrl'] as String?;
241268
if (wsUrl != null && wsUrl.isNotEmpty) {
242269
await cdp.reconnectTo(wsUrl);
243270
print(' ✅ Connected to existing tab: ${matchingTab['url']}');
244271
}
245-
// Only navigate if the tab isn't already on the exact URL
246272
final tabUrl = matchingTab['url'] as String? ?? '';
247-
if (tabUrl != url) {
273+
if (tabUrl == url) {
274+
// Already on exact URL — skip navigation
275+
} else if (isRootDomainMatch) {
276+
// Same root domain but different subdomain (e.g. login page redirected)
277+
// The tab is likely already logged in — skip navigation to avoid loops
278+
print(' ℹ️ Same root domain ($targetRoot), skipping re-navigation');
279+
} else {
280+
// Same origin, different path — navigate
248281
await cdp.call('Page.navigate', {'url': url});
249282
await Future.delayed(const Duration(seconds: 3));
250-
// Fallback: if page is broken (SPA anti-bot), retry via JS navigation
251283
await _retryWithJsNavIfBroken(cdp, url);
252284
}
253285
} else {

0 commit comments

Comments
 (0)