diff --git a/Base/res/html/error.html b/Base/res/html/error.html
new file mode 100644
index 0000000000..058ae0514a
--- /dev/null
+++ b/Base/res/html/error.html
@@ -0,0 +1,21 @@
+
+
+
+ Error!
+
+
+
+
+
+ Failed to load %s
+
+ Error: %s
+
+
diff --git a/Libraries/LibWeb/HtmlView.cpp b/Libraries/LibWeb/HtmlView.cpp
index c4224a9f7e..8d28fd4af3 100644
--- a/Libraries/LibWeb/HtmlView.cpp
+++ b/Libraries/LibWeb/HtmlView.cpp
@@ -346,23 +346,51 @@ void HtmlView::load(const URL& url)
if (on_load_start)
on_load_start(url);
- ResourceLoader::the().load(url, [this, url](auto data) {
- if (data.is_null()) {
- dbg() << "Load failed!";
- ASSERT_NOT_REACHED();
- }
+ ResourceLoader::the().load(
+ url,
+ [this, url](auto data) {
+ if (data.is_null()) {
+ load_error_page(url, "No data");
+ return;
+ }
- RefPtr document;
- if (url.path().ends_with(".png")) {
- document = create_image_document(data, url);
- } else {
- document = parse_html_document(data, url);
- }
- ASSERT(document);
- set_document(document);
- if (on_title_change)
- on_title_change(document->title());
- });
+ RefPtr document;
+ if (url.path().ends_with(".png")) {
+ document = create_image_document(data, url);
+ } else {
+ document = parse_html_document(data, url);
+ }
+ ASSERT(document);
+ set_document(document);
+ if (on_title_change)
+ on_title_change(document->title());
+ },
+ [this, url](auto error) {
+ load_error_page(url, error);
+ });
+}
+
+void HtmlView::load_error_page(const URL& failed_url, const String& error)
+{
+ auto error_page_url = "file:///res/html/error.html";
+ ResourceLoader::the().load(
+ error_page_url,
+ [this, failed_url, error](auto data) {
+ ASSERT(!data.is_null());
+ auto html = String::format(
+ String::copy(data).characters(),
+ escape_html_entities(failed_url.to_string()).characters(),
+ escape_html_entities(error).characters());
+ auto document = parse_html_document(html, failed_url);
+ ASSERT(document);
+ set_document(document);
+ if (on_title_change)
+ on_title_change(document->title());
+ },
+ [](auto error) {
+ dbg() << "Failed to load error page: " << error;
+ ASSERT_NOT_REACHED();
+ });
}
const LayoutDocument* HtmlView::layout_root() const
diff --git a/Libraries/LibWeb/HtmlView.h b/Libraries/LibWeb/HtmlView.h
index c287b4a3dd..0780224e63 100644
--- a/Libraries/LibWeb/HtmlView.h
+++ b/Libraries/LibWeb/HtmlView.h
@@ -50,6 +50,7 @@ public:
void reload();
void load(const URL&);
+ void load_error_page(const URL&, const String& error);
void scroll_to_anchor(const StringView&);
URL url() const;
diff --git a/Libraries/LibWeb/ResourceLoader.cpp b/Libraries/LibWeb/ResourceLoader.cpp
index ac11e40da0..daf2b813eb 100644
--- a/Libraries/LibWeb/ResourceLoader.cpp
+++ b/Libraries/LibWeb/ResourceLoader.cpp
@@ -26,9 +26,9 @@
#include
#include
-#include
#include
#include
+#include
namespace Web {
@@ -45,36 +45,37 @@ ResourceLoader::ResourceLoader()
{
}
-void ResourceLoader::load(const URL& url, Function callback)
+void ResourceLoader::load(const URL& url, Function success_callback, Function error_callback)
{
if (url.protocol() == "file") {
auto f = Core::File::construct();
f->set_filename(url.path());
if (!f->open(Core::IODevice::OpenMode::ReadOnly)) {
dbg() << "ResourceLoader::load: Error: " << f->error_string();
- callback({});
+ if (error_callback)
+ error_callback(f->error_string());
return;
}
auto data = f->read_all();
- deferred_invoke([data = move(data), callback = move(callback)](auto&) {
- callback(data);
+ deferred_invoke([data = move(data), success_callback = move(success_callback)](auto&) {
+ success_callback(data);
});
return;
}
if (url.protocol() == "http") {
auto download = protocol_client().start_download(url.to_string());
- download->on_finish = [this, callback = move(callback)](bool success, const ByteBuffer& payload, auto) {
+ download->on_finish = [this, success_callback = move(success_callback), error_callback = move(error_callback)](bool success, const ByteBuffer& payload, auto) {
--m_pending_loads;
if (on_load_counter_change)
on_load_counter_change();
if (!success) {
- dbg() << "HTTP load failed!";
- callback({});
+ if (error_callback)
+ error_callback("HTTP load failed");
return;
}
- callback(ByteBuffer::copy(payload.data(), payload.size()));
+ success_callback(ByteBuffer::copy(payload.data(), payload.size()));
};
++m_pending_loads;
if (on_load_counter_change)
@@ -82,8 +83,8 @@ void ResourceLoader::load(const URL& url, Function call
return;
}
- dbg() << "Unimplemented protocol: " << url.protocol();
- ASSERT_NOT_REACHED();
+ if (error_callback)
+ error_callback(String::format("Protocol not implemented: %s", url.protocol().characters()));
}
}
diff --git a/Libraries/LibWeb/ResourceLoader.h b/Libraries/LibWeb/ResourceLoader.h
index fafd5156fd..26f122bbf6 100644
--- a/Libraries/LibWeb/ResourceLoader.h
+++ b/Libraries/LibWeb/ResourceLoader.h
@@ -41,7 +41,7 @@ class ResourceLoader : public Core::Object {
public:
static ResourceLoader& the();
- void load(const URL&, Function);
+ void load(const URL&, Function success_callback, Function error_callback = nullptr);
Function on_load_counter_change;