浏览代码

Browser: Add error page

Add a simple HTML error page that gets loaded into the HtmlView when
loading the page fails.

Closes #1210 and #1516
Linus Groh 5 年之前
父节点
当前提交
021d78f8f7

+ 21 - 0
Base/res/html/error.html

@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>Error!</title>
+        <style>
+            h1 {
+                display: inline;
+            }
+            header {
+                margin-bottom: 10px;
+            }
+        </style>
+    </head>
+    <body>
+        <header>
+            <img src="file:///res/icons/32x32/msgbox-warning.png" alt="Warning" width="24" height="24">
+            <h1>Failed to load %s</h1>
+        </header>
+        <p>Error: %s</p>
+    </body>
+</html>

+ 44 - 16
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> 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> 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

+ 1 - 0
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;

+ 12 - 11
Libraries/LibWeb/ResourceLoader.cpp

@@ -26,9 +26,9 @@
 
 #include <AK/SharedBuffer.h>
 #include <LibCore/File.h>
-#include <LibWeb/ResourceLoader.h>
 #include <LibProtocol/Client.h>
 #include <LibProtocol/Download.h>
+#include <LibWeb/ResourceLoader.h>
 
 namespace Web {
 
@@ -45,36 +45,37 @@ ResourceLoader::ResourceLoader()
 {
 }
 
-void ResourceLoader::load(const URL& url, Function<void(const ByteBuffer&)> callback)
+void ResourceLoader::load(const URL& url, Function<void(const ByteBuffer&)> success_callback, Function<void(const String&)> 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<void(const ByteBuffer&)> call
         return;
     }
 
-    dbg() << "Unimplemented protocol: " << url.protocol();
-    ASSERT_NOT_REACHED();
+    if (error_callback)
+        error_callback(String::format("Protocol not implemented: %s", url.protocol().characters()));
 }
 
 }

+ 1 - 1
Libraries/LibWeb/ResourceLoader.h

@@ -41,7 +41,7 @@ class ResourceLoader : public Core::Object {
 public:
     static ResourceLoader& the();
 
-    void load(const URL&, Function<void(const ByteBuffer&)>);
+    void load(const URL&, Function<void(const ByteBuffer&)> success_callback, Function<void(const String&)> error_callback = nullptr);
 
     Function<void()> on_load_counter_change;