SEBWIN-362: Implemented basic load error page for browser.
This commit is contained in:
parent
049cf8fe19
commit
f0504fa6d2
11 changed files with 141 additions and 30 deletions
|
@ -17,6 +17,7 @@ using SafeExamBrowser.Browser.Contracts.Filters;
|
||||||
using SafeExamBrowser.Browser.Events;
|
using SafeExamBrowser.Browser.Events;
|
||||||
using SafeExamBrowser.Browser.Filters;
|
using SafeExamBrowser.Browser.Filters;
|
||||||
using SafeExamBrowser.Browser.Handlers;
|
using SafeExamBrowser.Browser.Handlers;
|
||||||
|
using SafeExamBrowser.Browser.Pages;
|
||||||
using SafeExamBrowser.Configuration.Contracts;
|
using SafeExamBrowser.Configuration.Contracts;
|
||||||
using SafeExamBrowser.I18n.Contracts;
|
using SafeExamBrowser.I18n.Contracts;
|
||||||
using SafeExamBrowser.Logging.Contracts;
|
using SafeExamBrowser.Logging.Contracts;
|
||||||
|
@ -115,6 +116,7 @@ namespace SafeExamBrowser.Browser
|
||||||
var displayHandler = new DisplayHandler();
|
var displayHandler = new DisplayHandler();
|
||||||
var downloadLogger = logger.CloneFor($"{nameof(DownloadHandler)} #{Id}");
|
var downloadLogger = logger.CloneFor($"{nameof(DownloadHandler)} #{Id}");
|
||||||
var downloadHandler = new DownloadHandler(appConfig, settings, downloadLogger);
|
var downloadHandler = new DownloadHandler(appConfig, settings, downloadLogger);
|
||||||
|
var htmlLoader = new HtmlLoader(text);
|
||||||
var keyboardHandler = new KeyboardHandler();
|
var keyboardHandler = new KeyboardHandler();
|
||||||
var lifeSpanHandler = new LifeSpanHandler();
|
var lifeSpanHandler = new LifeSpanHandler();
|
||||||
var requestFilter = new RequestFilter();
|
var requestFilter = new RequestFilter();
|
||||||
|
@ -138,7 +140,7 @@ namespace SafeExamBrowser.Browser
|
||||||
|
|
||||||
InitializeRequestFilter(requestFilter);
|
InitializeRequestFilter(requestFilter);
|
||||||
|
|
||||||
control = new BrowserControl(contextMenuHandler, dialogHandler, displayHandler, downloadHandler, keyboardHandler, lifeSpanHandler, requestHandler, startUrl);
|
control = new BrowserControl(contextMenuHandler, dialogHandler, displayHandler, downloadHandler, htmlLoader, keyboardHandler, lifeSpanHandler, requestHandler, startUrl);
|
||||||
control.AddressChanged += Control_AddressChanged;
|
control.AddressChanged += Control_AddressChanged;
|
||||||
control.LoadingStateChanged += Control_LoadingStateChanged;
|
control.LoadingStateChanged += Control_LoadingStateChanged;
|
||||||
control.TitleChanged += Control_TitleChanged;
|
control.TitleChanged += Control_TitleChanged;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
using CefSharp;
|
using CefSharp;
|
||||||
using CefSharp.WinForms;
|
using CefSharp.WinForms;
|
||||||
|
using SafeExamBrowser.Browser.Pages;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.Browser;
|
using SafeExamBrowser.UserInterface.Contracts.Browser;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.Browser.Events;
|
using SafeExamBrowser.UserInterface.Contracts.Browser.Events;
|
||||||
|
|
||||||
|
@ -19,6 +20,8 @@ namespace SafeExamBrowser.Browser
|
||||||
private IDialogHandler dialogHandler;
|
private IDialogHandler dialogHandler;
|
||||||
private IDisplayHandler displayHandler;
|
private IDisplayHandler displayHandler;
|
||||||
private IDownloadHandler downloadHandler;
|
private IDownloadHandler downloadHandler;
|
||||||
|
private string errorPage;
|
||||||
|
private HtmlLoader htmlLoader;
|
||||||
private IKeyboardHandler keyboardHandler;
|
private IKeyboardHandler keyboardHandler;
|
||||||
private ILifeSpanHandler lifeSpanHandler;
|
private ILifeSpanHandler lifeSpanHandler;
|
||||||
private IRequestHandler requestHandler;
|
private IRequestHandler requestHandler;
|
||||||
|
@ -53,6 +56,7 @@ namespace SafeExamBrowser.Browser
|
||||||
IDialogHandler dialogHandler,
|
IDialogHandler dialogHandler,
|
||||||
IDisplayHandler displayHandler,
|
IDisplayHandler displayHandler,
|
||||||
IDownloadHandler downloadHandler,
|
IDownloadHandler downloadHandler,
|
||||||
|
HtmlLoader htmlLoader,
|
||||||
IKeyboardHandler keyboardHandler,
|
IKeyboardHandler keyboardHandler,
|
||||||
ILifeSpanHandler lifeSpanHandler,
|
ILifeSpanHandler lifeSpanHandler,
|
||||||
IRequestHandler requestHandler,
|
IRequestHandler requestHandler,
|
||||||
|
@ -62,6 +66,7 @@ namespace SafeExamBrowser.Browser
|
||||||
this.dialogHandler = dialogHandler;
|
this.dialogHandler = dialogHandler;
|
||||||
this.displayHandler = displayHandler;
|
this.displayHandler = displayHandler;
|
||||||
this.downloadHandler = downloadHandler;
|
this.downloadHandler = downloadHandler;
|
||||||
|
this.htmlLoader = htmlLoader;
|
||||||
this.keyboardHandler = keyboardHandler;
|
this.keyboardHandler = keyboardHandler;
|
||||||
this.lifeSpanHandler = lifeSpanHandler;
|
this.lifeSpanHandler = lifeSpanHandler;
|
||||||
this.requestHandler = requestHandler;
|
this.requestHandler = requestHandler;
|
||||||
|
@ -70,6 +75,7 @@ namespace SafeExamBrowser.Browser
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
AddressChanged += (o, args) => addressChanged?.Invoke(args.Address);
|
AddressChanged += (o, args) => addressChanged?.Invoke(args.Address);
|
||||||
|
LoadError += BrowserControl_LoadError;
|
||||||
LoadingStateChanged += (o, args) => loadingStateChanged?.Invoke(args.IsLoading);
|
LoadingStateChanged += (o, args) => loadingStateChanged?.Invoke(args.IsLoading);
|
||||||
TitleChanged += (o, args) => titleChanged?.Invoke(args.Title);
|
TitleChanged += (o, args) => titleChanged?.Invoke(args.Title);
|
||||||
|
|
||||||
|
@ -80,6 +86,8 @@ namespace SafeExamBrowser.Browser
|
||||||
LifeSpanHandler = lifeSpanHandler;
|
LifeSpanHandler = lifeSpanHandler;
|
||||||
MenuHandler = contextMenuHandler;
|
MenuHandler = contextMenuHandler;
|
||||||
RequestHandler = requestHandler;
|
RequestHandler = requestHandler;
|
||||||
|
|
||||||
|
errorPage = htmlLoader.LoadErrorPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void NavigateBackwards()
|
public void NavigateBackwards()
|
||||||
|
@ -111,5 +119,15 @@ namespace SafeExamBrowser.Browser
|
||||||
{
|
{
|
||||||
GetBrowser().SetZoomLevel(level);
|
GetBrowser().SetZoomLevel(level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void BrowserControl_LoadError(object sender, LoadErrorEventArgs e)
|
||||||
|
{
|
||||||
|
var html = string.Copy(errorPage);
|
||||||
|
|
||||||
|
html = html.Replace("%%STATUS%%", $"{e.ErrorText} ({e.ErrorCode})");
|
||||||
|
html = html.Replace("%%URL%%", e.FailedUrl);
|
||||||
|
|
||||||
|
e.Frame.LoadHtml(html, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,14 +8,12 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.IO;
|
|
||||||
using System.Net.Mime;
|
using System.Net.Mime;
|
||||||
using System.Reflection;
|
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using CefSharp;
|
using CefSharp;
|
||||||
using SafeExamBrowser.Browser.Contracts.Filters;
|
using SafeExamBrowser.Browser.Contracts.Filters;
|
||||||
using SafeExamBrowser.Browser.Filters;
|
using SafeExamBrowser.Browser.Pages;
|
||||||
using SafeExamBrowser.Configuration.Contracts;
|
using SafeExamBrowser.Configuration.Contracts;
|
||||||
using SafeExamBrowser.I18n.Contracts;
|
using SafeExamBrowser.I18n.Contracts;
|
||||||
using SafeExamBrowser.Logging.Contracts;
|
using SafeExamBrowser.Logging.Contracts;
|
||||||
|
@ -32,6 +30,7 @@ namespace SafeExamBrowser.Browser.Handlers
|
||||||
private string browserExamKey;
|
private string browserExamKey;
|
||||||
private IResourceHandler contentHandler;
|
private IResourceHandler contentHandler;
|
||||||
private IRequestFilter filter;
|
private IRequestFilter filter;
|
||||||
|
private HtmlLoader htmlLoader;
|
||||||
private ILogger logger;
|
private ILogger logger;
|
||||||
private IResourceHandler pageHandler;
|
private IResourceHandler pageHandler;
|
||||||
private BrowserSettings settings;
|
private BrowserSettings settings;
|
||||||
|
@ -42,6 +41,7 @@ namespace SafeExamBrowser.Browser.Handlers
|
||||||
this.appConfig = appConfig;
|
this.appConfig = appConfig;
|
||||||
this.algorithm = new SHA256Managed();
|
this.algorithm = new SHA256Managed();
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
|
this.htmlLoader = new HtmlLoader(text);
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
this.text = text;
|
this.text = text;
|
||||||
|
@ -186,9 +186,14 @@ namespace SafeExamBrowser.Browser.Handlers
|
||||||
|
|
||||||
private IResourceHandler ResourceHandlerFor(ResourceType resourceType)
|
private IResourceHandler ResourceHandlerFor(ResourceType resourceType)
|
||||||
{
|
{
|
||||||
if (contentHandler == default(IResourceHandler) || pageHandler == default(IResourceHandler))
|
if (contentHandler == default(IResourceHandler))
|
||||||
{
|
{
|
||||||
InitializeResourceHandlers();
|
contentHandler = CefSharp.ResourceHandler.FromString(htmlLoader.LoadBlockedContent());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pageHandler == default(IResourceHandler))
|
||||||
|
{
|
||||||
|
pageHandler = CefSharp.ResourceHandler.FromString(htmlLoader.LoadBlockedPage());
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (resourceType)
|
switch (resourceType)
|
||||||
|
@ -200,26 +205,5 @@ namespace SafeExamBrowser.Browser.Handlers
|
||||||
return contentHandler;
|
return contentHandler;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeResourceHandlers()
|
|
||||||
{
|
|
||||||
var assembly = Assembly.GetAssembly(typeof(RequestFilter));
|
|
||||||
var contentMessage = text.Get(TextKey.Browser_BlockedContentMessage);
|
|
||||||
var contentStream = assembly.GetManifestResourceStream($"{typeof(RequestFilter).Namespace}.BlockedContent.html");
|
|
||||||
var pageButton = text.Get(TextKey.Browser_BlockedPageButton);
|
|
||||||
var pageMessage = text.Get(TextKey.Browser_BlockedPageMessage);
|
|
||||||
var pageTitle = text.Get(TextKey.Browser_BlockedPageTitle);
|
|
||||||
var pageStream = assembly.GetManifestResourceStream($"{typeof(RequestFilter).Namespace}.BlockedPage.html");
|
|
||||||
var contentHtml = new StreamReader(contentStream).ReadToEnd();
|
|
||||||
var pageHtml = new StreamReader(pageStream).ReadToEnd();
|
|
||||||
|
|
||||||
contentHtml = contentHtml.Replace("%%MESSAGE%%", contentMessage);
|
|
||||||
contentHandler = CefSharp.ResourceHandler.FromString(contentHtml);
|
|
||||||
|
|
||||||
pageHtml = pageHtml.Replace("%%MESSAGE%%", pageMessage).Replace("%%TITLE%%", pageTitle).Replace("%%BACK_BUTTON%%", pageButton);
|
|
||||||
pageHandler = CefSharp.ResourceHandler.FromString(pageHtml);
|
|
||||||
|
|
||||||
logger.Debug("Initialized resource handlers for blocked requests.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
75
SafeExamBrowser.Browser/Pages/HtmlLoader.cs
Normal file
75
SafeExamBrowser.Browser/Pages/HtmlLoader.cs
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 ETH Zürich, Educational Development and Technology (LET)
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
using SafeExamBrowser.I18n.Contracts;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Browser.Pages
|
||||||
|
{
|
||||||
|
internal class HtmlLoader
|
||||||
|
{
|
||||||
|
private IText text;
|
||||||
|
|
||||||
|
internal HtmlLoader(IText text)
|
||||||
|
{
|
||||||
|
this.text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal string LoadBlockedContent()
|
||||||
|
{
|
||||||
|
var assembly = Assembly.GetAssembly(typeof(HtmlLoader));
|
||||||
|
var path = $"{typeof(HtmlLoader).Namespace}.BlockedContent.html";
|
||||||
|
|
||||||
|
using (var stream = assembly.GetManifestResourceStream(path))
|
||||||
|
using (var reader = new StreamReader(stream))
|
||||||
|
{
|
||||||
|
var html = reader.ReadToEnd();
|
||||||
|
|
||||||
|
html = html.Replace("%%MESSAGE%%", text.Get(TextKey.Browser_BlockedContentMessage));
|
||||||
|
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal string LoadBlockedPage()
|
||||||
|
{
|
||||||
|
var assembly = Assembly.GetAssembly(typeof(HtmlLoader));
|
||||||
|
var path = $"{typeof(HtmlLoader).Namespace}.BlockedPage.html";
|
||||||
|
|
||||||
|
using (var stream = assembly.GetManifestResourceStream(path))
|
||||||
|
using (var reader = new StreamReader(stream))
|
||||||
|
{
|
||||||
|
var html = reader.ReadToEnd();
|
||||||
|
|
||||||
|
html = html.Replace("%%BACK_BUTTON%%", text.Get(TextKey.Browser_BlockedPageButton));
|
||||||
|
html = html.Replace("%%MESSAGE%%", text.Get(TextKey.Browser_BlockedPageMessage));
|
||||||
|
html = html.Replace("%%TITLE%%", text.Get(TextKey.Browser_BlockedPageTitle));
|
||||||
|
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal string LoadErrorPage()
|
||||||
|
{
|
||||||
|
var assembly = Assembly.GetAssembly(typeof(HtmlLoader));
|
||||||
|
var path = $"{typeof(HtmlLoader).Namespace}.LoadError.html";
|
||||||
|
|
||||||
|
using (var stream = assembly.GetManifestResourceStream(path))
|
||||||
|
using (var reader = new StreamReader(stream))
|
||||||
|
{
|
||||||
|
var html = reader.ReadToEnd();
|
||||||
|
|
||||||
|
html = html.Replace("%%MESSAGE%%", text.Get(TextKey.Browser_LoadErrorPageMessage));
|
||||||
|
html = html.Replace("%%TITLE%%", text.Get(TextKey.Browser_LoadErrorPageTitle));
|
||||||
|
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
SafeExamBrowser.Browser/Pages/LoadError.html
Normal file
14
SafeExamBrowser.Browser/Pages/LoadError.html
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html style="height: 100%; width: 100%">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>%%TITLE%%</title>
|
||||||
|
</head>
|
||||||
|
<body style="background-color: lightgray; display: table; font-family: 'Segoe UI'; height: 98%; text-align: center; width: 99%">
|
||||||
|
<div style="display: table-cell; vertical-align: middle">
|
||||||
|
<h1 style="color: red">%%TITLE%%</h1>
|
||||||
|
<p>%%MESSAGE%%</p>
|
||||||
|
<p style="font-weight: bold">%%STATUS%%</p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -91,6 +91,7 @@
|
||||||
<Compile Include="Handlers\LifeSpanHandler.cs" />
|
<Compile Include="Handlers\LifeSpanHandler.cs" />
|
||||||
<Compile Include="Handlers\RequestHandler.cs" />
|
<Compile Include="Handlers\RequestHandler.cs" />
|
||||||
<Compile Include="Handlers\ResourceHandler.cs" />
|
<Compile Include="Handlers\ResourceHandler.cs" />
|
||||||
|
<Compile Include="Pages\HtmlLoader.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -129,8 +130,11 @@
|
||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Include="Filters\BlockedContent.html" />
|
<EmbeddedResource Include="Pages\BlockedContent.html" />
|
||||||
<EmbeddedResource Include="Filters\BlockedPage.html" />
|
<EmbeddedResource Include="Pages\BlockedPage.html" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="Pages\LoadError.html" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|
|
@ -20,6 +20,8 @@ namespace SafeExamBrowser.I18n.Contracts
|
||||||
Browser_BlockedPageButton,
|
Browser_BlockedPageButton,
|
||||||
Browser_BlockedPageMessage,
|
Browser_BlockedPageMessage,
|
||||||
Browser_BlockedPageTitle,
|
Browser_BlockedPageTitle,
|
||||||
|
Browser_LoadErrorPageMessage,
|
||||||
|
Browser_LoadErrorPageTitle,
|
||||||
Browser_Name,
|
Browser_Name,
|
||||||
Browser_Tooltip,
|
Browser_Tooltip,
|
||||||
BrowserWindow_DeveloperConsoleMenuItem,
|
BrowserWindow_DeveloperConsoleMenuItem,
|
||||||
|
|
|
@ -18,6 +18,12 @@
|
||||||
<Entry key="Browser_BlockedPageTitle">
|
<Entry key="Browser_BlockedPageTitle">
|
||||||
Seite blockiert
|
Seite blockiert
|
||||||
</Entry>
|
</Entry>
|
||||||
|
<Entry key="Browser_LoadErrorPageMessage">
|
||||||
|
Beim Laden der Seite "%%URL%%" ist folgender Fehler aufgetreten:
|
||||||
|
</Entry>
|
||||||
|
<Entry key="Browser_LoadErrorPageTitle">
|
||||||
|
Seiten-Ladefehler
|
||||||
|
</Entry>
|
||||||
<Entry key="Browser_Name">
|
<Entry key="Browser_Name">
|
||||||
Browser
|
Browser
|
||||||
</Entry>
|
</Entry>
|
||||||
|
@ -139,7 +145,7 @@
|
||||||
Automatisches Beenden fehlgeschlagen
|
Automatisches Beenden fehlgeschlagen
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="MessageBox_BrowserNavigationBlocked">
|
<Entry key="MessageBox_BrowserNavigationBlocked">
|
||||||
Zugriff auf "%%URL%%" is gemäss der aktiven Konfiguration nicht erlaubt.
|
Zugriff auf "%%URL%%" ist gemäss der aktiven Konfiguration nicht erlaubt.
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="MessageBox_BrowserNavigationBlockedTitle">
|
<Entry key="MessageBox_BrowserNavigationBlockedTitle">
|
||||||
Seite blockiert
|
Seite blockiert
|
||||||
|
|
|
@ -18,6 +18,12 @@
|
||||||
<Entry key="Browser_BlockedPageTitle">
|
<Entry key="Browser_BlockedPageTitle">
|
||||||
Page Blocked
|
Page Blocked
|
||||||
</Entry>
|
</Entry>
|
||||||
|
<Entry key="Browser_LoadErrorPageMessage">
|
||||||
|
An error occurred while loading page "%%URL%%":
|
||||||
|
</Entry>
|
||||||
|
<Entry key="Browser_LoadErrorPageTitle">
|
||||||
|
Page Load Error
|
||||||
|
</Entry>
|
||||||
<Entry key="Browser_Name">
|
<Entry key="Browser_Name">
|
||||||
Browser
|
Browser
|
||||||
</Entry>
|
</Entry>
|
||||||
|
|
Loading…
Reference in a new issue