mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-14 19:29:36 +01:00
Implement res:// protocol for WebView, MIME type handling.
This commit is contained in:
75
Robust.Client.WebView/Cef/WebViewManagerCef.Mime.cs
Normal file
75
Robust.Client.WebView/Cef/WebViewManagerCef.Mime.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.WebView.Cef;
|
||||
|
||||
internal sealed partial class WebViewManagerCef
|
||||
{
|
||||
// Loosely based on:
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
|
||||
private readonly Dictionary<string, string> _resourceMimeTypes = new()
|
||||
{
|
||||
{ "aac", "audio/aac" },
|
||||
{ "avif", "image/avif" },
|
||||
{ "avi", "video/x-msvideo" },
|
||||
{ "bmp", "image/bmp" },
|
||||
{ "css", "text/css" },
|
||||
{ "gif", "image/gif" },
|
||||
{ "htm", "text/html" },
|
||||
{ "html", "text/html" },
|
||||
{ "ico", "image/vnd.microsoft.icon" },
|
||||
{ "jpeg", "image/jpeg" },
|
||||
{ "jpg", "image/jpeg" },
|
||||
{ "js", "text/javascript" },
|
||||
{ "json", "application/json" },
|
||||
{ "jsonld", "application/ld+json" },
|
||||
{ "midi", "audio/midi" },
|
||||
{ "mid", "audio/midi" },
|
||||
{ "mjs", "text/javascript" },
|
||||
{ "mp3", "audio/mpeg" },
|
||||
{ "mp4", "video/mp4" },
|
||||
{ "mpeg", "video/mpeg" },
|
||||
{ "oga", "audio/ogg" },
|
||||
{ "ogg", "audio/ogg" },
|
||||
{ "ogv", "video/ogg" },
|
||||
{ "ogx", "application/ogg" },
|
||||
{ "opus", "audio/opus" },
|
||||
{ "otf", "font/otf" },
|
||||
{ "png", "image/png" },
|
||||
{ "pdf", "application/pdf" },
|
||||
{ "svg", "image/svg+xml" },
|
||||
{ "tiff", "image/tiff" },
|
||||
{ "tif", "image/tiff" },
|
||||
{ "ts", "video/mp2t" },
|
||||
{ "ttf", "font/ttf" },
|
||||
{ "txt", "text/plain" },
|
||||
{ "wav", "audio/wav" },
|
||||
{ "weba", "audio/webm" },
|
||||
{ "webm", "video/webm" },
|
||||
{ "webp", "image/webp" },
|
||||
{ "woff", "font/woff" },
|
||||
{ "woff2", "font/woff2" },
|
||||
{ "xhtml", "application/xhtml+xml" },
|
||||
{ "xml", "application/xml" },
|
||||
{ "zip", "application/zip" },
|
||||
};
|
||||
|
||||
public void SetResourceMimeType(string extension, string mimeType)
|
||||
{
|
||||
DebugTools.Assert(!extension.StartsWith("."), "SetResourceMimeType extension must not include starting dot.");
|
||||
|
||||
lock (_resourceMimeTypes)
|
||||
{
|
||||
_resourceMimeTypes[extension] = mimeType;
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryGetResourceMimeType(string extension, [NotNullWhen(true)] out string? mimeType)
|
||||
{
|
||||
lock (_resourceMimeTypes)
|
||||
{
|
||||
return _resourceMimeTypes.TryGetValue(extension, out mimeType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,9 @@ using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Robust.Client.Console;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
@@ -23,6 +25,7 @@ namespace Robust.Client.WebView.Cef
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IResourceManagerInternal _resourceManager = default!;
|
||||
[Dependency] private readonly IClientConsoleHost _consoleHost = default!;
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
@@ -76,6 +79,12 @@ namespace Robust.Client.WebView.Cef
|
||||
// TODO CEF: After this point, debugging breaks. No, literally. My client crashes but ONLY with the debugger.
|
||||
// I have tried using the DEBUG and RELEASE versions of libcef.so, stripped or non-stripped...
|
||||
// And nothing seemed to work. Odd.
|
||||
|
||||
if (_cfg.GetCVar(WCVars.WebResProtocol))
|
||||
{
|
||||
var handler = new ResourceSchemeFactoryHandler(this, _resourceManager, Logger.GetSawmill("web.res"));
|
||||
CefRuntime.RegisterSchemeHandlerFactory("res", "", handler);
|
||||
}
|
||||
}
|
||||
|
||||
private static string? LocateCefResources()
|
||||
@@ -119,5 +128,48 @@ namespace Robust.Client.WebView.Cef
|
||||
{
|
||||
CefRuntime.Shutdown();
|
||||
}
|
||||
|
||||
private sealed class ResourceSchemeFactoryHandler : CefSchemeHandlerFactory
|
||||
{
|
||||
private readonly WebViewManagerCef _parent;
|
||||
private readonly IResourceManager _resourceManager;
|
||||
private readonly ISawmill _sawmill;
|
||||
|
||||
public ResourceSchemeFactoryHandler(
|
||||
WebViewManagerCef parent,
|
||||
IResourceManager resourceManager,
|
||||
ISawmill sawmill)
|
||||
{
|
||||
_parent = parent;
|
||||
_resourceManager = resourceManager;
|
||||
_sawmill = sawmill;
|
||||
}
|
||||
|
||||
protected override CefResourceHandler Create(
|
||||
CefBrowser browser,
|
||||
CefFrame frame,
|
||||
string schemeName,
|
||||
CefRequest request)
|
||||
{
|
||||
var uri = new Uri(request.Url);
|
||||
|
||||
_sawmill.Debug($"HANDLING: {request.Url}");
|
||||
|
||||
var resourcePath = new ResourcePath(uri.AbsolutePath);
|
||||
if (_resourceManager.TryContentFileRead(resourcePath, out var stream))
|
||||
{
|
||||
if (!_parent.TryGetResourceMimeType(resourcePath.Extension, out var mime))
|
||||
mime = "application/octet-stream";
|
||||
|
||||
return new RequestResultStream(stream, mime, HttpStatusCode.OK).MakeHandler();
|
||||
}
|
||||
|
||||
var notFoundStream = new MemoryStream();
|
||||
notFoundStream.Write(Encoding.UTF8.GetBytes("Not found"));
|
||||
notFoundStream.Position = 0;
|
||||
|
||||
return new RequestResultStream(notFoundStream, "text/plain", HttpStatusCode.NotFound).MakeHandler();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface;
|
||||
|
||||
@@ -11,6 +12,17 @@ namespace Robust.Client.WebView.Headless
|
||||
return new WebViewWindowDummy();
|
||||
}
|
||||
|
||||
public void SetResourceMimeType(string extension, string mimeType)
|
||||
{
|
||||
// Nop
|
||||
}
|
||||
|
||||
public bool TryGetResourceMimeType(string extension, [NotNullWhen(true)] out string? mimeType)
|
||||
{
|
||||
mimeType = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public IWebViewControlImpl MakeControlImpl(WebViewControl owner)
|
||||
{
|
||||
return new WebViewControlImplDummy();
|
||||
|
||||
@@ -1,7 +1,40 @@
|
||||
namespace Robust.Client.WebView
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Robust.Client.WebView
|
||||
{
|
||||
public interface IWebViewManager
|
||||
{
|
||||
IWebViewWindow CreateBrowserWindow(BrowserWindowCreateParameters createParams);
|
||||
|
||||
/// <summary>
|
||||
/// Overrides file extension -> mime type mappings for the <c>res://</c> protocol.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The built-in <c>res://</c> protocol needs to guess MIME types to report to CEF when resolving files.
|
||||
/// A limited set of extensions have pre-set MIME types in the engine.
|
||||
/// This method allows you to replace or add entries if need be.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// This method is thread safe.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="extension">
|
||||
/// The extension to specify the MIME type for.
|
||||
/// The argument must not include the starting "." of the file extension.
|
||||
/// </param>
|
||||
/// <param name="mimeType">The mime type for this file extension.</param>
|
||||
/// <seealso cref="TryGetResourceMimeType"/>
|
||||
void SetResourceMimeType(string extension, string mimeType);
|
||||
|
||||
/// <summary>
|
||||
/// Tries to resolve an entry from the <see cref="SetResourceMimeType"/> list.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This method is thread safe.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
bool TryGetResourceMimeType(string extension, [NotNullWhen(true)] out string? mimeType);
|
||||
}
|
||||
}
|
||||
|
||||
17
Robust.Client.WebView/WCVars.cs
Normal file
17
Robust.Client.WebView/WCVars.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using Robust.Shared.Configuration;
|
||||
|
||||
namespace Robust.Client.WebView;
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
/// <summary>
|
||||
/// CVars for <c>Robust.Client.WebView</c>
|
||||
/// </summary>
|
||||
[CVarDefs]
|
||||
public static class WCVars
|
||||
{
|
||||
/// <summary>
|
||||
/// Enable the <c>res://</c> protocol inside WebView browsers, allowing access to the Robust resources.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<bool> WebResProtocol =
|
||||
CVarDef.Create("web.res_protocol", true, CVar.CLIENTONLY);
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
using Robust.Client.WebView;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Robust.Client.WebView;
|
||||
using Robust.Client.WebView.Cef;
|
||||
using Robust.Client.WebView.Headless;
|
||||
using Robust.Client.WebViewHook;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
@@ -17,6 +19,9 @@ namespace Robust.Client.WebView
|
||||
{
|
||||
DebugTools.Assert(_impl == null, "WebViewManager has already been initialized!");
|
||||
|
||||
var cfg = IoCManager.Resolve<IConfigurationManagerInternal>();
|
||||
cfg.LoadCVarsFromAssembly(typeof(WebViewManager).Assembly);
|
||||
|
||||
IoCManager.RegisterInstance<IWebViewManager>(this);
|
||||
IoCManager.RegisterInstance<IWebViewManagerInternal>(this);
|
||||
|
||||
@@ -49,6 +54,20 @@ namespace Robust.Client.WebView
|
||||
return _impl!.CreateBrowserWindow(createParams);
|
||||
}
|
||||
|
||||
public void SetResourceMimeType(string extension, string mimeType)
|
||||
{
|
||||
DebugTools.Assert(_impl != null, "WebViewManager has not yet been initialized!");
|
||||
|
||||
_impl!.SetResourceMimeType(extension, mimeType);
|
||||
}
|
||||
|
||||
public bool TryGetResourceMimeType(string extension, [NotNullWhen(true)] out string? mimeType)
|
||||
{
|
||||
DebugTools.Assert(_impl != null, "WebViewManager has not yet been initialized!");
|
||||
|
||||
return _impl!.TryGetResourceMimeType(extension, out mimeType);
|
||||
}
|
||||
|
||||
public IWebViewControlImpl MakeControlImpl(WebViewControl owner)
|
||||
{
|
||||
DebugTools.Assert(_impl != null, "WebViewManager has not yet been initialized!");
|
||||
|
||||
Reference in New Issue
Block a user