mirror of
https://github.com/rmcrackan/Libation.git
synced 2026-10-28 08:29:11 -04:00
- Set NativeWebDialog.UserAgent in AdapterCreated instead of passing a full User-Agent header to ApplicationNameForUserAgent (which caused WebKit2GTK webkit_settings_set_user_agent assertion failures on Linux). - Set gtkArgs.ForceX11GdkBackend = true when requesting the GTK WebView environment. - Recognize GTK initialization failures (InvalidOperationException 'Unable to initialize GTK', libgtk-3/libgdk-3 DllNotFoundException, and exceptions originating from GtkNativeWebViewDialog/AvaloniaGtk) in WebView2LoginErrorMessage so async void NativeWebDialog.Show() failures fault BrowserLoginAsync instead of leaving tcs.Task waiting forever, allowing StartAsyncInternal to fall back to LoginExternalDialog.
This commit is contained in:
1 parent
e1c52d910b
commit
f61bbe5b68
3 files changed
+96
-7
No files matched your search
@@ -93,6 +93,15 @@ public class AvaloniaLoginChoiceEager : ILoginChoiceEager
|
||||
};
|
||||
dialog.AdapterCreated += (s, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
dialog.UserAgent = Configuration.Instance.GetDeviceRegistrationProfile().UserAgent;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Serilog.Log.Logger.Warning(ex, "Failed to set WebView User-Agent");
|
||||
}
|
||||
|
||||
if (dialog.TryGetCookieManager() is NativeWebViewCookieManager cookieManager)
|
||||
{
|
||||
foreach (System.Net.Cookie c in shoiceIn.SignInCookies ?? [])
|
||||
@@ -126,10 +135,13 @@ public class AvaloniaLoginChoiceEager : ILoginChoiceEager
|
||||
return null;
|
||||
}
|
||||
|
||||
// NativeWebDialog can fault on a posted dispatcher job (e.g. missing libwebkit2gtk on Linux), which bypasses a try/catch around Show().
|
||||
// NativeWebDialog.Show() is async void and can fault on a posted dispatcher job (e.g. missing libwebkit2gtk
|
||||
// or GTK initialization failure on Linux), which bypasses a synchronous try/catch around Show() and would
|
||||
// otherwise leave tcs.Task waiting forever.
|
||||
void onUnhandledException(object? sender, DispatcherUnhandledExceptionEventArgs e)
|
||||
{
|
||||
if (!WebView2LoginErrorMessage.IsWebView2SignInInfrastructureFailure(e.Exception))
|
||||
if (!WebView2LoginErrorMessage.IsWebView2SignInInfrastructureFailure(e.Exception)
|
||||
&& !WebView2LoginErrorMessage.TryFindInTree(e.Exception, out _))
|
||||
return;
|
||||
e.Handled = true;
|
||||
try
|
||||
@@ -166,7 +178,7 @@ public class AvaloniaLoginChoiceEager : ILoginChoiceEager
|
||||
else
|
||||
dialog.Show();
|
||||
}
|
||||
catch (Exception ex) when (WebView2LoginErrorMessage.IsWebView2SignInInfrastructureFailure(ex))
|
||||
catch (Exception ex)
|
||||
{
|
||||
tcs.TrySetException(ex);
|
||||
}
|
||||
@@ -190,11 +202,10 @@ public class AvaloniaLoginChoiceEager : ILoginChoiceEager
|
||||
break;
|
||||
case AppleWKWebViewEnvironmentRequestedEventArgs appleArgs:
|
||||
appleArgs.NonPersistentDataStore = true;
|
||||
appleArgs.ApplicationNameForUserAgent = userAgent;
|
||||
break;
|
||||
case GtkWebViewEnvironmentRequestedEventArgs gtkArgs:
|
||||
gtkArgs.EphemeralDataManager = true;
|
||||
gtkArgs.ApplicationNameForUserAgent = userAgent;
|
||||
gtkArgs.ForceX11GdkBackend = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,10 +61,15 @@ public static class WebView2LoginErrorMessage
|
||||
if (e is DllNotFoundException dll && IsEmbeddedWebViewNativeDllFailure(dll))
|
||||
return true;
|
||||
|
||||
// AvaloniaGtk.RunTask throws InvalidOperationException("Unable to initialize GTK") when GTK cannot start
|
||||
// (for example on Wayland without X11 backend or when no GTK display is available).
|
||||
if (e is InvalidOperationException && e.Message.Contains("Unable to initialize GTK", StringComparison.OrdinalIgnoreCase))
|
||||
return true;
|
||||
|
||||
if (!StackMentionsEmbeddedSignInBrowser(e))
|
||||
continue;
|
||||
|
||||
if (e is UnauthorizedAccessException)
|
||||
if (e is UnauthorizedAccessException or InvalidOperationException or EntryPointNotFoundException or TypeInitializationException)
|
||||
return true;
|
||||
|
||||
if (e is COMException com
|
||||
@@ -81,7 +86,9 @@ public static class WebView2LoginErrorMessage
|
||||
private static bool IsEmbeddedWebViewNativeDllFailure(DllNotFoundException e)
|
||||
{
|
||||
if (e.Message.Contains("libwebkit2gtk", StringComparison.OrdinalIgnoreCase)
|
||||
|| e.Message.Contains("webkit2gtk", StringComparison.OrdinalIgnoreCase))
|
||||
|| e.Message.Contains("webkit2gtk", StringComparison.OrdinalIgnoreCase)
|
||||
|| e.Message.Contains("libgtk-3", StringComparison.OrdinalIgnoreCase)
|
||||
|| e.Message.Contains("libgdk-3", StringComparison.OrdinalIgnoreCase))
|
||||
return true;
|
||||
|
||||
return StackMentionsEmbeddedSignInBrowser(e);
|
||||
@@ -118,7 +125,9 @@ public static class WebView2LoginErrorMessage
|
||||
&& (stack.Contains("WebView2", StringComparison.Ordinal)
|
||||
|| stack.Contains("CoreWebView2", StringComparison.Ordinal)
|
||||
|| stack.Contains("NativeWebDialog", StringComparison.Ordinal)
|
||||
|| stack.Contains("GtkNativeWebViewDialog", StringComparison.Ordinal)
|
||||
|| stack.Contains("GtkWebView", StringComparison.Ordinal)
|
||||
|| stack.Contains("AvaloniaGtk", StringComparison.Ordinal)
|
||||
|| stack.Contains("WebViewControlAvalonia", StringComparison.Ordinal));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using LibationUiBase;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace LibationUiBase.Tests;
|
||||
|
||||
[TestClass]
|
||||
public class WebView2LoginErrorMessageTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void missing_webkit2gtk_dll_is_recognized_without_stack_trace()
|
||||
{
|
||||
var ex = new DllNotFoundException("Unable to load shared library 'libwebkit2gtk-4.1.so.0'");
|
||||
|
||||
Assert.IsTrue(WebView2LoginErrorMessage.IsWebView2SignInInfrastructureFailure(ex));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void missing_gtk3_dll_is_recognized_without_stack_trace()
|
||||
{
|
||||
var ex = new DllNotFoundException("Unable to load shared library 'libgtk-3.so.0'");
|
||||
|
||||
Assert.IsTrue(WebView2LoginErrorMessage.IsWebView2SignInInfrastructureFailure(ex));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void gtk_initialization_failure_is_recognized_without_stack_trace()
|
||||
{
|
||||
var ex = new InvalidOperationException("Unable to initialize GTK");
|
||||
|
||||
Assert.IsTrue(WebView2LoginErrorMessage.IsWebView2SignInInfrastructureFailure(ex));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void invalid_operation_from_avalonia_gtk_webview_stack_is_recognized()
|
||||
{
|
||||
Exception? caught = null;
|
||||
try
|
||||
{
|
||||
FakeAvaloniaGtkStack.ThrowFromGtkNativeWebViewDialog();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
caught = ex;
|
||||
}
|
||||
|
||||
Assert.IsNotNull(caught);
|
||||
Assert.IsTrue(WebView2LoginErrorMessage.IsWebView2SignInInfrastructureFailure(caught));
|
||||
var agg = new AggregateException(new Exception("outer"), caught);
|
||||
Assert.IsTrue(WebView2LoginErrorMessage.TryFindInTree(agg, out var match));
|
||||
Assert.IsNotNull(match);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void unrelated_invalid_operation_is_not_treated_as_webview_failure()
|
||||
{
|
||||
var ex = new InvalidOperationException("Something else went wrong");
|
||||
|
||||
Assert.IsFalse(WebView2LoginErrorMessage.IsWebView2SignInInfrastructureFailure(ex));
|
||||
}
|
||||
|
||||
private static class FakeAvaloniaGtkStack
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static void ThrowFromGtkNativeWebViewDialog()
|
||||
=> throw new InvalidOperationException("Avalonia.X11 is not referenced");
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user