2020-06-06 13:02:44 +02:00
|
|
|
|
/*
|
|
|
|
|
|
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
|
|
|
|
|
*
|
2021-04-22 01:24:48 -07:00
|
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
2020-06-06 13:02:44 +02:00
|
|
|
|
*/
|
|
|
|
|
|
|
2021-01-17 18:17:00 +01:00
|
|
|
|
#include <AK/Debug.h>
|
2021-08-11 06:09:35 +08:00
|
|
|
|
#include <AK/JsonArray.h>
|
2020-06-06 13:02:44 +02:00
|
|
|
|
#include <AK/LexicalPath.h>
|
2021-04-22 00:00:06 +02:00
|
|
|
|
#include <AK/SourceGenerator.h>
|
2020-06-06 13:02:44 +02:00
|
|
|
|
#include <LibGemini/Document.h>
|
|
|
|
|
|
#include <LibGfx/ImageDecoder.h>
|
|
|
|
|
|
#include <LibMarkdown/Document.h>
|
2022-02-12 16:02:56 +02:00
|
|
|
|
#include <LibWeb/Cookie/ParsedCookie.h>
|
2020-06-25 23:50:35 +02:00
|
|
|
|
#include <LibWeb/DOM/Document.h>
|
2020-06-06 13:02:44 +02:00
|
|
|
|
#include <LibWeb/DOM/ElementFactory.h>
|
|
|
|
|
|
#include <LibWeb/DOM/Text.h>
|
2021-11-18 15:01:28 +01:00
|
|
|
|
#include <LibWeb/HTML/BrowsingContext.h>
|
2020-09-22 17:53:40 +02:00
|
|
|
|
#include <LibWeb/HTML/HTMLIFrameElement.h>
|
2021-09-25 23:15:48 +02:00
|
|
|
|
#include <LibWeb/HTML/Parser/HTMLParser.h>
|
2021-11-20 10:56:36 +01:00
|
|
|
|
#include <LibWeb/ImageDecoding.h>
|
2020-06-06 13:02:44 +02:00
|
|
|
|
#include <LibWeb/Loader/FrameLoader.h>
|
|
|
|
|
|
#include <LibWeb/Loader/ResourceLoader.h>
|
2020-07-28 19:27:41 +02:00
|
|
|
|
#include <LibWeb/Page/Page.h>
|
2020-06-06 13:02:44 +02:00
|
|
|
|
|
|
|
|
|
|
namespace Web {
|
|
|
|
|
|
|
2021-08-07 04:28:22 +08:00
|
|
|
|
static RefPtr<Gfx::Bitmap> s_default_favicon_bitmap;
|
|
|
|
|
|
|
2021-11-18 15:01:28 +01:00
|
|
|
|
FrameLoader::FrameLoader(HTML::BrowsingContext& browsing_context)
|
2021-05-30 12:36:53 +02:00
|
|
|
|
: m_browsing_context(browsing_context)
|
2020-06-06 13:02:44 +02:00
|
|
|
|
{
|
2021-08-07 04:28:22 +08:00
|
|
|
|
if (!s_default_favicon_bitmap) {
|
2022-01-03 22:20:01 -05:00
|
|
|
|
s_default_favicon_bitmap = Gfx::Bitmap::try_load_from_file("/res/icons/16x16/app-browser.png").release_value_but_fixme_should_propagate_errors();
|
2021-08-07 04:28:22 +08:00
|
|
|
|
VERIFY(s_default_favicon_bitmap);
|
|
|
|
|
|
}
|
2020-06-06 13:02:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FrameLoader::~FrameLoader()
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-12-13 17:38:03 +01:00
|
|
|
|
static bool build_markdown_document(DOM::Document& document, const ByteBuffer& data)
|
2020-06-06 13:02:44 +02:00
|
|
|
|
{
|
|
|
|
|
|
auto markdown_document = Markdown::Document::parse(data);
|
|
|
|
|
|
if (!markdown_document)
|
2020-12-13 17:38:03 +01:00
|
|
|
|
return false;
|
2020-06-06 13:02:44 +02:00
|
|
|
|
|
2021-09-25 23:15:48 +02:00
|
|
|
|
HTML::HTMLParser parser(document, markdown_document->render_to_html(), "utf-8");
|
2020-12-13 17:38:03 +01:00
|
|
|
|
parser.run(document.url());
|
|
|
|
|
|
return true;
|
2020-06-06 13:02:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-12-13 17:38:03 +01:00
|
|
|
|
static bool build_text_document(DOM::Document& document, const ByteBuffer& data)
|
2020-06-06 13:02:44 +02:00
|
|
|
|
{
|
2020-12-13 17:38:03 +01:00
|
|
|
|
auto html_element = document.create_element("html");
|
|
|
|
|
|
document.append_child(html_element);
|
2020-06-06 13:02:44 +02:00
|
|
|
|
|
2020-12-13 17:38:03 +01:00
|
|
|
|
auto head_element = document.create_element("head");
|
2020-06-06 13:02:44 +02:00
|
|
|
|
html_element->append_child(head_element);
|
2020-12-13 17:38:03 +01:00
|
|
|
|
auto title_element = document.create_element("title");
|
2020-06-06 13:02:44 +02:00
|
|
|
|
head_element->append_child(title_element);
|
|
|
|
|
|
|
2020-12-13 17:38:03 +01:00
|
|
|
|
auto title_text = document.create_text_node(document.url().basename());
|
2020-06-06 13:02:44 +02:00
|
|
|
|
title_element->append_child(title_text);
|
|
|
|
|
|
|
2020-12-13 17:38:03 +01:00
|
|
|
|
auto body_element = document.create_element("body");
|
2020-06-06 13:02:44 +02:00
|
|
|
|
html_element->append_child(body_element);
|
|
|
|
|
|
|
2020-12-13 17:38:03 +01:00
|
|
|
|
auto pre_element = document.create_element("pre");
|
2020-06-06 13:02:44 +02:00
|
|
|
|
body_element->append_child(pre_element);
|
|
|
|
|
|
|
2020-12-13 17:38:03 +01:00
|
|
|
|
pre_element->append_child(document.create_text_node(String::copy(data)));
|
|
|
|
|
|
return true;
|
2020-06-06 13:02:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-11-20 10:56:36 +01:00
|
|
|
|
static bool build_image_document(DOM::Document& document, ByteBuffer const& data)
|
2020-06-06 13:02:44 +02:00
|
|
|
|
{
|
2021-11-20 10:56:36 +01:00
|
|
|
|
NonnullRefPtr decoder = image_decoder_client();
|
|
|
|
|
|
auto image = decoder->decode_image(data);
|
|
|
|
|
|
if (!image.has_value() || image->frames.is_empty())
|
2021-07-27 01:12:53 +02:00
|
|
|
|
return false;
|
2021-11-20 10:56:36 +01:00
|
|
|
|
auto const& frame = image->frames[0];
|
|
|
|
|
|
auto const& bitmap = frame.bitmap;
|
2020-12-13 17:38:03 +01:00
|
|
|
|
if (!bitmap)
|
|
|
|
|
|
return false;
|
2020-06-06 13:02:44 +02:00
|
|
|
|
|
2020-12-13 17:38:03 +01:00
|
|
|
|
auto html_element = document.create_element("html");
|
|
|
|
|
|
document.append_child(html_element);
|
2020-06-06 13:02:44 +02:00
|
|
|
|
|
2020-12-13 17:38:03 +01:00
|
|
|
|
auto head_element = document.create_element("head");
|
2020-06-06 13:02:44 +02:00
|
|
|
|
html_element->append_child(head_element);
|
2020-12-13 17:38:03 +01:00
|
|
|
|
auto title_element = document.create_element("title");
|
2020-06-06 13:02:44 +02:00
|
|
|
|
head_element->append_child(title_element);
|
|
|
|
|
|
|
2021-06-29 16:46:16 +02:00
|
|
|
|
auto basename = LexicalPath::basename(document.url().path());
|
2021-04-23 16:46:57 +02:00
|
|
|
|
auto title_text = adopt_ref(*new DOM::Text(document, String::formatted("{} [{}x{}]", basename, bitmap->width(), bitmap->height())));
|
2020-06-06 13:02:44 +02:00
|
|
|
|
title_element->append_child(title_text);
|
|
|
|
|
|
|
2020-12-13 17:38:03 +01:00
|
|
|
|
auto body_element = document.create_element("body");
|
2020-06-06 13:02:44 +02:00
|
|
|
|
html_element->append_child(body_element);
|
|
|
|
|
|
|
2020-12-13 17:38:03 +01:00
|
|
|
|
auto image_element = document.create_element("img");
|
|
|
|
|
|
image_element->set_attribute(HTML::AttributeNames::src, document.url().to_string());
|
2020-06-06 13:02:44 +02:00
|
|
|
|
body_element->append_child(image_element);
|
|
|
|
|
|
|
2020-12-13 17:38:03 +01:00
|
|
|
|
return true;
|
2020-06-06 13:02:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-12-13 17:38:03 +01:00
|
|
|
|
static bool build_gemini_document(DOM::Document& document, const ByteBuffer& data)
|
2020-06-06 13:02:44 +02:00
|
|
|
|
{
|
2020-10-06 11:08:37 -04:00
|
|
|
|
StringView gemini_data { data };
|
2020-12-13 17:38:03 +01:00
|
|
|
|
auto gemini_document = Gemini::Document::parse(gemini_data, document.url());
|
2020-10-06 11:08:37 -04:00
|
|
|
|
String html_data = gemini_document->render_to_html();
|
|
|
|
|
|
|
2021-05-01 21:10:08 +02:00
|
|
|
|
dbgln_if(GEMINI_DEBUG, "Gemini data:\n\"\"\"{}\"\"\"", gemini_data);
|
|
|
|
|
|
dbgln_if(GEMINI_DEBUG, "Converted to HTML:\n\"\"\"{}\"\"\"", html_data);
|
2020-06-06 13:02:44 +02:00
|
|
|
|
|
2021-09-25 23:15:48 +02:00
|
|
|
|
HTML::HTMLParser parser(document, html_data, "utf-8");
|
2020-12-13 17:38:03 +01:00
|
|
|
|
parser.run(document.url());
|
|
|
|
|
|
return true;
|
2020-06-06 13:02:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-12-13 17:38:03 +01:00
|
|
|
|
bool FrameLoader::parse_document(DOM::Document& document, const ByteBuffer& data)
|
2020-06-06 13:02:44 +02:00
|
|
|
|
{
|
2020-12-13 17:38:03 +01:00
|
|
|
|
auto& mime_type = document.content_type();
|
2020-09-07 19:45:14 +02:00
|
|
|
|
if (mime_type == "text/html" || mime_type == "image/svg+xml") {
|
2021-09-25 23:15:48 +02:00
|
|
|
|
auto parser = HTML::HTMLParser::create_with_uncertain_encoding(document, data);
|
2021-05-12 10:47:12 +02:00
|
|
|
|
parser->run(document.url());
|
2020-12-13 17:38:03 +01:00
|
|
|
|
return true;
|
2020-09-07 19:45:14 +02:00
|
|
|
|
}
|
2020-12-13 17:38:03 +01:00
|
|
|
|
if (mime_type.starts_with("image/"))
|
|
|
|
|
|
return build_image_document(document, data);
|
2021-03-20 18:46:22 +04:00
|
|
|
|
if (mime_type == "text/plain" || mime_type == "application/json")
|
2020-12-13 17:38:03 +01:00
|
|
|
|
return build_text_document(document, data);
|
|
|
|
|
|
if (mime_type == "text/markdown")
|
|
|
|
|
|
return build_markdown_document(document, data);
|
|
|
|
|
|
if (mime_type == "text/gemini")
|
|
|
|
|
|
return build_gemini_document(document, data);
|
|
|
|
|
|
|
|
|
|
|
|
return false;
|
2020-06-06 13:02:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-09-11 21:15:15 -07:00
|
|
|
|
bool FrameLoader::load(LoadRequest& request, Type type)
|
2020-06-06 13:02:44 +02:00
|
|
|
|
{
|
2020-09-28 11:55:26 +02:00
|
|
|
|
if (!request.is_valid()) {
|
|
|
|
|
|
load_error_page(request.url(), "Invalid request");
|
2020-06-06 13:02:44 +02:00
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-05-30 12:36:53 +02:00
|
|
|
|
if (!m_browsing_context.is_frame_nesting_allowed(request.url())) {
|
2021-04-19 14:30:08 +02:00
|
|
|
|
dbgln("No further recursion is allowed for the frame, abort load!");
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-09-28 11:55:26 +02:00
|
|
|
|
auto& url = request.url();
|
|
|
|
|
|
|
2021-05-29 01:27:06 +01:00
|
|
|
|
if (type == Type::Navigation || type == Type::Reload) {
|
2021-05-30 12:36:53 +02:00
|
|
|
|
if (auto* page = browsing_context().page())
|
2020-11-12 18:23:05 +01:00
|
|
|
|
page->client().page_did_start_loading(url);
|
|
|
|
|
|
}
|
2020-06-06 13:02:44 +02:00
|
|
|
|
|
2022-02-17 23:23:01 +00:00
|
|
|
|
// https://fetch.spec.whatwg.org/#concept-fetch
|
|
|
|
|
|
// Step 12: If request’s header list does not contain `Accept`, then:
|
|
|
|
|
|
// 1. Let value be `*/*`. (NOTE: Not necessary as we're about to override it)
|
|
|
|
|
|
// 2. A user agent should set value to the first matching statement, if any, switching on request’s destination:
|
|
|
|
|
|
// -> "document"
|
|
|
|
|
|
// -> "frame"
|
|
|
|
|
|
// -> "iframe"
|
|
|
|
|
|
// `text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8`
|
|
|
|
|
|
// FIXME: This should be case-insensitive.
|
|
|
|
|
|
if (!request.headers().contains("Accept"))
|
|
|
|
|
|
request.set_header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
|
|
|
|
|
|
|
2021-05-29 01:17:36 +01:00
|
|
|
|
set_resource(ResourceLoader::the().load_resource(Resource::Type::Generic, request));
|
|
|
|
|
|
|
2020-11-07 09:03:52 +00:00
|
|
|
|
if (type == Type::IFrame)
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
|
|
if (url.protocol() == "http" || url.protocol() == "https") {
|
2021-09-13 00:33:23 +03:00
|
|
|
|
AK::URL favicon_url;
|
2020-06-06 13:02:44 +02:00
|
|
|
|
favicon_url.set_protocol(url.protocol());
|
|
|
|
|
|
favicon_url.set_host(url.host());
|
2021-09-13 23:12:16 +03:00
|
|
|
|
favicon_url.set_port(url.port_or_default());
|
2021-05-27 21:27:51 +02:00
|
|
|
|
favicon_url.set_paths({ "favicon.ico" });
|
2020-06-06 13:02:44 +02:00
|
|
|
|
|
|
|
|
|
|
ResourceLoader::the().load(
|
|
|
|
|
|
favicon_url,
|
2021-04-03 15:11:36 +02:00
|
|
|
|
[this, favicon_url](auto data, auto&, auto) {
|
2021-08-07 16:37:26 +08:00
|
|
|
|
dbgln_if(SPAM_DEBUG, "Favicon downloaded, {} bytes from {}", data.size(), favicon_url);
|
2021-09-24 20:28:03 +05:30
|
|
|
|
if (data.is_empty())
|
|
|
|
|
|
return;
|
2021-08-07 04:28:22 +08:00
|
|
|
|
RefPtr<Gfx::Bitmap> favicon_bitmap;
|
2021-11-20 11:25:46 +01:00
|
|
|
|
auto decoded_image = image_decoder_client().decode_image(data);
|
|
|
|
|
|
if (!decoded_image.has_value() || decoded_image->frames.is_empty()) {
|
|
|
|
|
|
dbgln("Could not decode favicon {}", favicon_url);
|
2021-08-07 04:28:22 +08:00
|
|
|
|
} else {
|
2021-11-20 11:25:46 +01:00
|
|
|
|
favicon_bitmap = decoded_image->frames[0].bitmap;
|
|
|
|
|
|
dbgln_if(IMAGE_DECODER_DEBUG, "Decoded favicon, {}", favicon_bitmap->size());
|
2021-07-27 01:12:53 +02:00
|
|
|
|
}
|
2021-08-07 04:28:22 +08:00
|
|
|
|
load_favicon(favicon_bitmap);
|
|
|
|
|
|
},
|
|
|
|
|
|
[this](auto&, auto) {
|
|
|
|
|
|
load_favicon();
|
2020-06-06 13:02:44 +02:00
|
|
|
|
});
|
2021-08-07 04:28:22 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
load_favicon();
|
2020-06-06 13:02:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-09-13 00:33:23 +03:00
|
|
|
|
bool FrameLoader::load(const AK::URL& url, Type type)
|
2020-09-28 11:55:26 +02:00
|
|
|
|
{
|
2021-08-07 16:37:26 +08:00
|
|
|
|
dbgln_if(SPAM_DEBUG, "FrameLoader::load: {}", url);
|
2020-09-28 11:55:26 +02:00
|
|
|
|
|
|
|
|
|
|
if (!url.is_valid()) {
|
|
|
|
|
|
load_error_page(url, "Invalid URL");
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-05-30 12:36:53 +02:00
|
|
|
|
auto request = LoadRequest::create_for_url_on_page(url, browsing_context().page());
|
2020-09-28 11:55:26 +02:00
|
|
|
|
return load(request, type);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-11-11 00:55:02 +01:00
|
|
|
|
void FrameLoader::load_html(StringView html, const AK::URL& url)
|
2020-10-08 21:03:16 +01:00
|
|
|
|
{
|
2020-12-13 16:59:22 +01:00
|
|
|
|
auto document = DOM::Document::create(url);
|
2021-09-25 23:15:48 +02:00
|
|
|
|
HTML::HTMLParser parser(document, html, "utf-8");
|
2020-10-08 21:03:16 +01:00
|
|
|
|
parser.run(url);
|
2021-09-09 13:14:32 +02:00
|
|
|
|
browsing_context().set_active_document(&parser.document());
|
2020-10-08 21:03:16 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-01-12 01:01:33 +11:00
|
|
|
|
// FIXME: Use an actual templating engine (our own one when it's built, preferably
|
|
|
|
|
|
// with a way to check these usages at compile time)
|
|
|
|
|
|
|
2021-09-13 00:33:23 +03:00
|
|
|
|
void FrameLoader::load_error_page(const AK::URL& failed_url, const String& error)
|
2020-06-06 13:02:44 +02:00
|
|
|
|
{
|
|
|
|
|
|
auto error_page_url = "file:///res/html/error.html";
|
|
|
|
|
|
ResourceLoader::the().load(
|
|
|
|
|
|
error_page_url,
|
2021-04-03 15:11:36 +02:00
|
|
|
|
[this, failed_url, error](auto data, auto&, auto) {
|
2021-02-23 20:42:32 +01:00
|
|
|
|
VERIFY(!data.is_null());
|
2021-04-22 00:00:06 +02:00
|
|
|
|
StringBuilder builder;
|
|
|
|
|
|
SourceGenerator generator { builder };
|
2021-04-22 10:17:00 +02:00
|
|
|
|
generator.set("failed_url", escape_html_entities(failed_url.to_string()));
|
|
|
|
|
|
generator.set("error", escape_html_entities(error));
|
2021-04-22 00:00:06 +02:00
|
|
|
|
generator.append(data);
|
|
|
|
|
|
auto document = HTML::parse_html_document(generator.as_string_view(), failed_url, "utf-8");
|
2021-02-23 20:42:32 +01:00
|
|
|
|
VERIFY(document);
|
2021-09-09 13:14:32 +02:00
|
|
|
|
browsing_context().set_active_document(document);
|
2020-06-06 13:02:44 +02:00
|
|
|
|
},
|
2021-04-03 15:11:36 +02:00
|
|
|
|
[](auto& error, auto) {
|
2021-01-17 18:17:00 +01:00
|
|
|
|
dbgln("Failed to load error page: {}", error);
|
2021-02-23 20:42:32 +01:00
|
|
|
|
VERIFY_NOT_REACHED();
|
2020-06-06 13:02:44 +02:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-08-07 04:28:22 +08:00
|
|
|
|
void FrameLoader::load_favicon(RefPtr<Gfx::Bitmap> bitmap)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (auto* page = browsing_context().page()) {
|
|
|
|
|
|
if (bitmap)
|
|
|
|
|
|
page->client().page_did_change_favicon(*bitmap);
|
|
|
|
|
|
else
|
|
|
|
|
|
page->client().page_did_change_favicon(*s_default_favicon_bitmap);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-02-12 16:02:56 +02:00
|
|
|
|
void FrameLoader::store_response_cookies(AK::URL const& url, String const& cookies)
|
|
|
|
|
|
{
|
|
|
|
|
|
auto* page = browsing_context().page();
|
|
|
|
|
|
if (!page)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
auto set_cookie_json_value = MUST(JsonValue::from_string(cookies));
|
|
|
|
|
|
VERIFY(set_cookie_json_value.type() == JsonValue::Type::Array);
|
|
|
|
|
|
|
|
|
|
|
|
for (const auto& set_cookie_entry : set_cookie_json_value.as_array().values()) {
|
|
|
|
|
|
VERIFY(set_cookie_entry.type() == JsonValue::Type::String);
|
|
|
|
|
|
|
|
|
|
|
|
auto cookie = Cookie::parse_cookie(set_cookie_entry.as_string());
|
|
|
|
|
|
if (!cookie.has_value())
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
page->client().page_did_set_cookie(url, cookie.value(), Cookie::Source::Http); // FIXME: Determine cookie source correctly
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-06-06 13:38:08 +02:00
|
|
|
|
void FrameLoader::resource_did_load()
|
|
|
|
|
|
{
|
|
|
|
|
|
auto url = resource()->url();
|
|
|
|
|
|
|
2022-02-12 16:02:56 +02:00
|
|
|
|
if (auto set_cookie = resource()->response_headers().get("Set-Cookie"); set_cookie.has_value())
|
|
|
|
|
|
store_response_cookies(url, *set_cookie);
|
|
|
|
|
|
|
2022-02-12 15:42:48 +02:00
|
|
|
|
// For 3xx (Redirection) responses, the Location value refers to the preferred target resource for automatically redirecting the request.
|
|
|
|
|
|
auto status_code = resource()->status_code();
|
|
|
|
|
|
if (status_code.has_value() && *status_code >= 300 && *status_code <= 399) {
|
|
|
|
|
|
auto location = resource()->response_headers().get("Location");
|
|
|
|
|
|
if (location.has_value()) {
|
|
|
|
|
|
if (m_redirects_count > maximum_redirects_allowed) {
|
|
|
|
|
|
m_redirects_count = 0;
|
|
|
|
|
|
load_error_page(url, "Too many redirects");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
m_redirects_count++;
|
|
|
|
|
|
load(url.complete_url(location.value()), FrameLoader::Type::Navigation);
|
2021-05-11 22:22:56 +03:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2020-06-06 13:38:08 +02:00
|
|
|
|
}
|
2021-05-11 22:22:56 +03:00
|
|
|
|
m_redirects_count = 0;
|
2020-06-06 13:38:08 +02:00
|
|
|
|
|
2021-06-20 12:22:43 +01:00
|
|
|
|
if (!resource()->has_encoded_data()) {
|
|
|
|
|
|
load_error_page(url, "No data");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-05-12 10:21:00 +02:00
|
|
|
|
if (resource()->has_encoding()) {
|
2021-08-07 16:37:26 +08:00
|
|
|
|
dbgln_if(RESOURCE_DEBUG, "This content has MIME type '{}', encoding '{}'", resource()->mime_type(), resource()->encoding().value());
|
2021-05-12 10:21:00 +02:00
|
|
|
|
} else {
|
2021-08-07 16:37:26 +08:00
|
|
|
|
dbgln_if(RESOURCE_DEBUG, "This content has MIME type '{}', encoding unknown", resource()->mime_type());
|
2021-05-12 10:21:00 +02:00
|
|
|
|
}
|
2020-12-13 17:38:03 +01:00
|
|
|
|
|
|
|
|
|
|
auto document = DOM::Document::create();
|
|
|
|
|
|
document->set_url(url);
|
2021-05-12 10:32:41 +02:00
|
|
|
|
document->set_encoding(resource()->encoding());
|
2020-12-13 17:38:03 +01:00
|
|
|
|
document->set_content_type(resource()->mime_type());
|
2020-06-06 14:06:37 +02:00
|
|
|
|
|
2021-09-09 13:14:32 +02:00
|
|
|
|
browsing_context().set_active_document(document);
|
2020-12-13 17:38:03 +01:00
|
|
|
|
|
|
|
|
|
|
if (!parse_document(*document, resource()->encoded_data())) {
|
2020-06-06 14:06:37 +02:00
|
|
|
|
load_error_page(url, "Failed to parse content.");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-06-06 13:38:08 +02:00
|
|
|
|
if (!url.fragment().is_empty())
|
2021-05-30 12:36:53 +02:00
|
|
|
|
browsing_context().scroll_to_anchor(url.fragment());
|
2021-09-08 11:56:50 +02:00
|
|
|
|
else
|
|
|
|
|
|
browsing_context().set_viewport_scroll_offset({ 0, 0 });
|
2020-09-22 17:53:40 +02:00
|
|
|
|
|
2021-05-30 12:36:53 +02:00
|
|
|
|
if (auto* page = browsing_context().page())
|
2020-12-08 21:44:42 +01:00
|
|
|
|
page->client().page_did_finish_loading(url);
|
2020-06-06 13:38:08 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void FrameLoader::resource_did_fail()
|
|
|
|
|
|
{
|
|
|
|
|
|
load_error_page(resource()->url(), resource()->error());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-06-06 13:02:44 +02:00
|
|
|
|
}
|