mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-04 14:20:58 +00:00
Percent-Encode Local File URLs for Embedded Web Pages (#15961)
* Percent-Encode Local File URLs for Embedded Web Pages The Home tab, setup wizard, Project tab and other embedded pages were loaded from file:// URLs built by pasting the resources path into a string. A '#', '%' or '?' in the install path was then read as a URL fragment, escape or query, so the pages failed to load, for example a portable install under D:\#OneDrive showed a directory listing instead of the setup wizard. Add file_url_from_path(), built on wxFileSystem::FileNameToURL, and use it wherever a local page or image URL is built from a path. Queries such as ?lang= are appended after the path is encoded. The wizard's printer cover images are passed to the page as file URLs too. * Encode the Login Error Page URL and Cover More Windows Path Forms The login dialog's error page was still loaded from a raw resources path; it now uses file_url_from_path like the other local pages. The Windows file URL tests now also cover a resources path joined with a forward-slash relative path, as the callers build them, and a UNC path. * Build the Flush Dialog Page URLs with the Shared Helper WipingDialog and NozzleListTable still called wxFileSystem::FileNameToURL directly. They now go through file_url_from_path like every other local page, so the URLs are built in one place. Adds a test for a resources directory with a '#' in its name, which the plugin page check did not recognise before.
This commit is contained in:
@@ -27,6 +27,7 @@ add_executable(${_TEST_NAME}_tests
|
||||
test_plugin_cloud_metadata.cpp
|
||||
test_plugin_audit.cpp
|
||||
test_shortcuts.cpp
|
||||
test_file_url.cpp
|
||||
../fff_print/test_helpers.cpp
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
|
||||
#include "slic3r/GUI/GUI.hpp"
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#include <wx/uri.h>
|
||||
|
||||
using namespace Slic3r::GUI;
|
||||
|
||||
#ifndef _WIN32
|
||||
TEST_CASE("A file URL keeps characters special to URLs in its path", "[FileUrl]")
|
||||
{
|
||||
const std::string path = GENERATE(as<std::string>{},
|
||||
"/opt/test#dir/resources/web/homepage/index.html",
|
||||
"/opt/test%20x/resources/web/homepage/index.html",
|
||||
"/opt/Orca Slicer/resources/web/homepage/index.html",
|
||||
"/opt/what?/resources/web/homepage/index.html",
|
||||
"/home/Jos\xC3\xA9/\xE8\xB5\x84\xE6\xBA\x90/resources/web/homepage/index.html");
|
||||
|
||||
const wxString url = file_url_from_path(boost::filesystem::path(path));
|
||||
CAPTURE(path, url.utf8_string());
|
||||
|
||||
// WebView::CreateWebView() and WebView::LoadUrl() re-parse the URL before loading it.
|
||||
const wxURI uri(wxURI(url).BuildURI());
|
||||
CHECK(uri.GetScheme() == "file");
|
||||
CHECK(!uri.HasQuery());
|
||||
CHECK(!uri.HasFragment());
|
||||
CHECK(wxURI::Unescape(uri.GetPath()).utf8_string() == path);
|
||||
}
|
||||
|
||||
TEST_CASE("A file URL of a plain path is the path behind file://", "[FileUrl]")
|
||||
{
|
||||
const std::string path = "/opt/OrcaSlicer/resources/web/homepage/index.html";
|
||||
CHECK(file_url_from_path(boost::filesystem::path(path)) == "file://" + path);
|
||||
}
|
||||
|
||||
TEST_CASE("A query appended to a file URL stays separate from its path", "[FileUrl]")
|
||||
{
|
||||
const std::string path = "/opt/test#dir%20x/resources/web/guide/0/index.html";
|
||||
const wxURI uri(file_url_from_path(boost::filesystem::path(path)) + "?target=21&lang=de");
|
||||
CHECK(wxURI::Unescape(uri.GetPath()).utf8_string() == path);
|
||||
CHECK(uri.GetQuery() == "target=21&lang=de");
|
||||
CHECK(!uri.HasFragment());
|
||||
}
|
||||
#else
|
||||
TEST_CASE("A file URL of a Windows path has a drive letter and forward slashes", "[FileUrl]")
|
||||
{
|
||||
const auto [path, url] = GENERATE(table<std::wstring, std::string>({
|
||||
{ L"C:\\Program Files\\OrcaSlicer\\resources\\web\\homepage\\index.html",
|
||||
"file:///C:/Program%20Files/OrcaSlicer/resources/web/homepage/index.html" },
|
||||
{ L"D:\\#OneDrive\\OrcaSlicer\\resources\\web\\guide\\0\\index.html",
|
||||
"file:///D:/%23OneDrive/OrcaSlicer/resources/web/guide/0/index.html" },
|
||||
{ L"D:\\100%\\OrcaSlicer\\resources\\web\\homepage\\index.html",
|
||||
"file:///D:/100%25/OrcaSlicer/resources/web/homepage/index.html" },
|
||||
// Callers join the resources directory with a forward-slash relative path.
|
||||
{ L"D:\\#OneDrive\\OrcaSlicer\\resources/web/homepage/index.html",
|
||||
"file:///D:/%23OneDrive/OrcaSlicer/resources/web/homepage/index.html" },
|
||||
{ L"\\\\server\\share\\OrcaSlicer\\resources\\web\\homepage\\index.html",
|
||||
"file://server/share/OrcaSlicer/resources/web/homepage/index.html" },
|
||||
}));
|
||||
CHECK(file_url_from_path(boost::filesystem::path(path)).utf8_string() == url);
|
||||
}
|
||||
|
||||
TEST_CASE("A query appended to a Windows file URL stays separate from its path", "[FileUrl]")
|
||||
{
|
||||
const wxURI uri(file_url_from_path(boost::filesystem::path(L"D:\\#OneDrive\\OrcaSlicer\\resources\\web\\guide\\0\\index.html")) +
|
||||
"?target=21&lang=de");
|
||||
CHECK(wxURI::Unescape(uri.GetPath()) == "/D:/#OneDrive/OrcaSlicer/resources/web/guide/0/index.html");
|
||||
CHECK(uri.GetQuery() == "target=21&lang=de");
|
||||
CHECK(!uri.HasFragment());
|
||||
}
|
||||
#endif
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <wx/uri.h>
|
||||
|
||||
namespace py = pybind11;
|
||||
|
||||
namespace {
|
||||
@@ -210,23 +212,33 @@ TEST_CASE("A reloaded plugin page is recognised by its base URL, fragment aside"
|
||||
{
|
||||
using namespace Slic3r::GUI::web_hosting;
|
||||
|
||||
// A resources path holding a space, which the web view reports escaped.
|
||||
// A resources path holding a space, which the web view may report escaped differently.
|
||||
const Slic3r::ScopedResourcesDir resources("web content check");
|
||||
|
||||
// The swapped-in page, then after an in-page anchor and a reload.
|
||||
CHECK(is_content_url(content_base_url()));
|
||||
CHECK(is_content_url(content_base_url() + "#tab2"));
|
||||
wxString escaped = content_base_url();
|
||||
escaped.Replace(" ", "%20");
|
||||
REQUIRE(escaped != content_base_url());
|
||||
CHECK(is_content_url(escaped));
|
||||
CHECK(is_content_url(escaped + "#tab2"));
|
||||
const wxString unescaped = wxURI::Unescape(content_base_url());
|
||||
REQUIRE(unescaped != content_base_url());
|
||||
CHECK(is_content_url(unescaped));
|
||||
CHECK(is_content_url(unescaped + "#tab2"));
|
||||
// A page the plugin linked to keeps its own URL and must be left alone.
|
||||
CHECK_FALSE(is_content_url(content_base_url() + "guide.html"));
|
||||
CHECK_FALSE(is_content_url("https://example.com/"));
|
||||
CHECK_FALSE(is_content_url(""));
|
||||
}
|
||||
|
||||
TEST_CASE("A reloaded plugin page is recognised when the resources path holds a '#'", "[PluginHost]")
|
||||
{
|
||||
using namespace Slic3r::GUI::web_hosting;
|
||||
|
||||
const Slic3r::ScopedResourcesDir resources("web#content check");
|
||||
|
||||
CHECK(is_content_url(content_base_url()));
|
||||
CHECK(is_content_url(content_base_url() + "#tab2"));
|
||||
CHECK_FALSE(is_content_url(content_base_url() + "guide.html"));
|
||||
}
|
||||
|
||||
TEST_CASE("Plugin host API exposes model geometry and structure to Python", "[PluginHost][Python]")
|
||||
{
|
||||
using Catch::Matchers::WithinAbs;
|
||||
|
||||
Reference in New Issue
Block a user