Skip to content

Commit e647f2a

Browse files
committed
Proposal of fixing external navigation.
1 parent 9f79f51 commit e647f2a

File tree

2 files changed

+89
-0
lines changed

2 files changed

+89
-0
lines changed

src/Components/Endpoints/src/DependencyInjection/HttpNavigationManager.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,52 @@ protected override void NavigateToCore(string uri, NavigationOptions options)
2323
}
2424
else
2525
{
26+
if (!IsInternalUri(absoluteUriString))
27+
{
28+
// it's an external navigation, avoid Uri validation exception
29+
BaseUri = GetBaseUriFromAbsoluteUri(absoluteUriString);
30+
}
2631
Uri = absoluteUriString;
2732
NotifyLocationChanged(isInterceptedLink: false);
2833
}
2934
}
35+
36+
// ToDo: the following are copy-paste, consider refactoring to a common place
37+
private bool IsInternalUri(string uri)
38+
{
39+
var normalizedBaseUri = NormalizeBaseUri(BaseUri);
40+
return uri.StartsWith(normalizedBaseUri, StringComparison.OrdinalIgnoreCase);
41+
}
42+
43+
private static string GetBaseUriFromAbsoluteUri(string absoluteUri)
44+
{
45+
// Find the position of the first single slash after the scheme (e.g., "https://")
46+
var schemeDelimiterIndex = absoluteUri.IndexOf("://", StringComparison.Ordinal);
47+
if (schemeDelimiterIndex == -1)
48+
{
49+
throw new ArgumentException($"The provided URI '{absoluteUri}' is not a valid absolute URI.");
50+
}
51+
52+
// Find the end of the authority section (e.g., "https://example.com/")
53+
var authorityEndIndex = absoluteUri.IndexOf('/', schemeDelimiterIndex + 3);
54+
if (authorityEndIndex == -1)
55+
{
56+
// If no slash is found, the entire URI is the authority (e.g., "https://example.com")
57+
return NormalizeBaseUri(absoluteUri + "/");
58+
}
59+
60+
// Extract the base URI up to the authority section
61+
return NormalizeBaseUri(absoluteUri.Substring(0, authorityEndIndex + 1));
62+
}
63+
64+
private static string NormalizeBaseUri(string baseUri)
65+
{
66+
var lastSlashIndex = baseUri.LastIndexOf('/');
67+
if (lastSlashIndex >= 0)
68+
{
69+
baseUri = baseUri.Substring(0, lastSlashIndex + 1);
70+
}
71+
72+
return baseUri;
73+
}
3074
}

src/Components/Server/src/Circuits/RemoteNavigationManager.cs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,14 @@ protected override void NavigateToCore(string uri, NavigationOptions options)
9797
}
9898
else
9999
{
100+
if (!IsInternalUri(absoluteUriString))
101+
{
102+
// it's an external navigation, avoid Uri validation exception
103+
BaseUri = GetBaseUriFromAbsoluteUri(absoluteUriString);
104+
}
100105
Uri = absoluteUriString;
101106
NotifyLocationChanged(isInterceptedLink: false);
107+
return;
102108
}
103109
}
104110

@@ -134,6 +140,44 @@ async Task PerformNavigationAsync()
134140
}
135141
}
136142

143+
private bool IsInternalUri(string uri)
144+
{
145+
var normalizedBaseUri = NormalizeBaseUri(BaseUri);
146+
return uri.StartsWith(normalizedBaseUri, StringComparison.OrdinalIgnoreCase);
147+
}
148+
149+
private static string GetBaseUriFromAbsoluteUri(string absoluteUri)
150+
{
151+
// Find the position of the first single slash after the scheme (e.g., "https://")
152+
var schemeDelimiterIndex = absoluteUri.IndexOf("://", StringComparison.Ordinal);
153+
if (schemeDelimiterIndex == -1)
154+
{
155+
throw new ArgumentException($"The provided URI '{absoluteUri}' is not a valid absolute URI.");
156+
}
157+
158+
// Find the end of the authority section (e.g., "https://example.com/")
159+
var authorityEndIndex = absoluteUri.IndexOf('/', schemeDelimiterIndex + 3);
160+
if (authorityEndIndex == -1)
161+
{
162+
// If no slash is found, the entire URI is the authority (e.g., "https://example.com")
163+
return NormalizeBaseUri(absoluteUri + "/");
164+
}
165+
166+
// Extract the base URI up to the authority section
167+
return NormalizeBaseUri(absoluteUri.Substring(0, authorityEndIndex + 1));
168+
}
169+
170+
private static string NormalizeBaseUri(string baseUri)
171+
{
172+
var lastSlashIndex = baseUri.LastIndexOf('/');
173+
if (lastSlashIndex >= 0)
174+
{
175+
baseUri = baseUri.Substring(0, lastSlashIndex + 1);
176+
}
177+
178+
return baseUri;
179+
}
180+
137181
/// <inheritdoc />
138182
public override void Refresh(bool forceReload = false)
139183
{
@@ -148,6 +192,7 @@ public override void Refresh(bool forceReload = false)
148192
{
149193
Uri = absoluteUriString;
150194
NotifyLocationChanged(isInterceptedLink: false);
195+
return;
151196
}
152197
}
153198

0 commit comments

Comments
 (0)