mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 03:47:35 +00:00
Libraries: Move to Userland/Libraries/
This commit is contained in:
parent
dc28c07fa5
commit
13d7c09125
1857 changed files with 266 additions and 274 deletions
68
Userland/Libraries/LibWeb/Loader/ContentFilter.cpp
Normal file
68
Userland/Libraries/LibWeb/Loader/ContentFilter.cpp
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibWeb/Loader/ContentFilter.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
ContentFilter& ContentFilter::the()
|
||||
{
|
||||
static ContentFilter* filter = new ContentFilter;
|
||||
return *filter;
|
||||
}
|
||||
|
||||
ContentFilter::ContentFilter()
|
||||
{
|
||||
}
|
||||
|
||||
ContentFilter::~ContentFilter()
|
||||
{
|
||||
}
|
||||
|
||||
bool ContentFilter::is_filtered(const URL& url) const
|
||||
{
|
||||
auto url_string = url.to_string();
|
||||
|
||||
for (auto& pattern : m_patterns) {
|
||||
if (url_string.matches(pattern.text, CaseSensitivity::CaseSensitive))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ContentFilter::add_pattern(const String& pattern)
|
||||
{
|
||||
StringBuilder builder;
|
||||
if (!pattern.starts_with('*'))
|
||||
builder.append('*');
|
||||
builder.append(pattern);
|
||||
if (!pattern.ends_with('*'))
|
||||
builder.append('*');
|
||||
m_patterns.empend(builder.to_string());
|
||||
}
|
||||
|
||||
}
|
51
Userland/Libraries/LibWeb/Loader/ContentFilter.h
Normal file
51
Userland/Libraries/LibWeb/Loader/ContentFilter.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/URL.h>
|
||||
#include <AK/Vector.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
class ContentFilter {
|
||||
public:
|
||||
static ContentFilter& the();
|
||||
|
||||
bool is_filtered(const URL&) const;
|
||||
void add_pattern(const String&);
|
||||
|
||||
private:
|
||||
ContentFilter();
|
||||
~ContentFilter();
|
||||
|
||||
struct Pattern {
|
||||
String text;
|
||||
};
|
||||
Vector<Pattern> m_patterns;
|
||||
};
|
||||
|
||||
}
|
296
Userland/Libraries/LibWeb/Loader/FrameLoader.cpp
Normal file
296
Userland/Libraries/LibWeb/Loader/FrameLoader.cpp
Normal file
|
@ -0,0 +1,296 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <AK/LexicalPath.h>
|
||||
#include <LibGemini/Document.h>
|
||||
#include <LibGfx/ImageDecoder.h>
|
||||
#include <LibMarkdown/Document.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/ElementFactory.h>
|
||||
#include <LibWeb/DOM/Text.h>
|
||||
#include <LibWeb/HTML/HTMLIFrameElement.h>
|
||||
#include <LibWeb/HTML/Parser/HTMLDocumentParser.h>
|
||||
#include <LibWeb/Loader/FrameLoader.h>
|
||||
#include <LibWeb/Loader/ResourceLoader.h>
|
||||
#include <LibWeb/Namespace.h>
|
||||
#include <LibWeb/Page/Frame.h>
|
||||
#include <LibWeb/Page/Page.h>
|
||||
|
||||
//#define GEMINI_DEBUG 1
|
||||
|
||||
namespace Web {
|
||||
|
||||
FrameLoader::FrameLoader(Frame& frame)
|
||||
: m_frame(frame)
|
||||
{
|
||||
}
|
||||
|
||||
FrameLoader::~FrameLoader()
|
||||
{
|
||||
}
|
||||
|
||||
static bool build_markdown_document(DOM::Document& document, const ByteBuffer& data)
|
||||
{
|
||||
auto markdown_document = Markdown::Document::parse(data);
|
||||
if (!markdown_document)
|
||||
return false;
|
||||
|
||||
HTML::HTMLDocumentParser parser(document, markdown_document->render_to_html(), "utf-8");
|
||||
parser.run(document.url());
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool build_text_document(DOM::Document& document, const ByteBuffer& data)
|
||||
{
|
||||
auto html_element = document.create_element("html");
|
||||
document.append_child(html_element);
|
||||
|
||||
auto head_element = document.create_element("head");
|
||||
html_element->append_child(head_element);
|
||||
auto title_element = document.create_element("title");
|
||||
head_element->append_child(title_element);
|
||||
|
||||
auto title_text = document.create_text_node(document.url().basename());
|
||||
title_element->append_child(title_text);
|
||||
|
||||
auto body_element = document.create_element("body");
|
||||
html_element->append_child(body_element);
|
||||
|
||||
auto pre_element = document.create_element("pre");
|
||||
body_element->append_child(pre_element);
|
||||
|
||||
pre_element->append_child(document.create_text_node(String::copy(data)));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool build_image_document(DOM::Document& document, const ByteBuffer& data)
|
||||
{
|
||||
auto image_decoder = Gfx::ImageDecoder::create(data.data(), data.size());
|
||||
auto bitmap = image_decoder->bitmap();
|
||||
if (!bitmap)
|
||||
return false;
|
||||
|
||||
auto html_element = document.create_element("html");
|
||||
document.append_child(html_element);
|
||||
|
||||
auto head_element = document.create_element("head");
|
||||
html_element->append_child(head_element);
|
||||
auto title_element = document.create_element("title");
|
||||
head_element->append_child(title_element);
|
||||
|
||||
auto basename = LexicalPath(document.url().path()).basename();
|
||||
auto title_text = adopt(*new DOM::Text(document, String::formatted("{} [{}x{}]", basename, bitmap->width(), bitmap->height())));
|
||||
title_element->append_child(title_text);
|
||||
|
||||
auto body_element = document.create_element("body");
|
||||
html_element->append_child(body_element);
|
||||
|
||||
auto image_element = document.create_element("img");
|
||||
image_element->set_attribute(HTML::AttributeNames::src, document.url().to_string());
|
||||
body_element->append_child(image_element);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool build_gemini_document(DOM::Document& document, const ByteBuffer& data)
|
||||
{
|
||||
StringView gemini_data { data };
|
||||
auto gemini_document = Gemini::Document::parse(gemini_data, document.url());
|
||||
String html_data = gemini_document->render_to_html();
|
||||
|
||||
#ifdef GEMINI_DEBUG
|
||||
dbgln("Gemini data:\n\"\"\"{}\"\"\"", gemini_data);
|
||||
dbgln("Converted to HTML:\n\"\"\"{}\"\"\"", html_data);
|
||||
#endif
|
||||
|
||||
HTML::HTMLDocumentParser parser(document, html_data, "utf-8");
|
||||
parser.run(document.url());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FrameLoader::parse_document(DOM::Document& document, const ByteBuffer& data)
|
||||
{
|
||||
auto& mime_type = document.content_type();
|
||||
if (mime_type == "text/html" || mime_type == "image/svg+xml") {
|
||||
HTML::HTMLDocumentParser parser(document, data, document.encoding());
|
||||
parser.run(document.url());
|
||||
return true;
|
||||
}
|
||||
if (mime_type.starts_with("image/"))
|
||||
return build_image_document(document, data);
|
||||
if (mime_type == "text/plain")
|
||||
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;
|
||||
}
|
||||
|
||||
bool FrameLoader::load(const LoadRequest& request, Type type)
|
||||
{
|
||||
if (!request.is_valid()) {
|
||||
load_error_page(request.url(), "Invalid request");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& url = request.url();
|
||||
|
||||
set_resource(ResourceLoader::the().load_resource(Resource::Type::Generic, request));
|
||||
|
||||
if (type == Type::Navigation) {
|
||||
if (auto* page = frame().page())
|
||||
page->client().page_did_start_loading(url);
|
||||
}
|
||||
|
||||
if (type == Type::IFrame)
|
||||
return true;
|
||||
|
||||
if (url.protocol() == "http" || url.protocol() == "https") {
|
||||
URL favicon_url;
|
||||
favicon_url.set_protocol(url.protocol());
|
||||
favicon_url.set_host(url.host());
|
||||
favicon_url.set_port(url.port());
|
||||
favicon_url.set_path("/favicon.ico");
|
||||
|
||||
ResourceLoader::the().load(
|
||||
favicon_url,
|
||||
[this, favicon_url](auto data, auto&) {
|
||||
dbg() << "Favicon downloaded, " << data.size() << " bytes from " << favicon_url;
|
||||
auto decoder = Gfx::ImageDecoder::create(data.data(), data.size());
|
||||
auto bitmap = decoder->bitmap();
|
||||
if (!bitmap) {
|
||||
dbg() << "Could not decode favicon " << favicon_url;
|
||||
return;
|
||||
}
|
||||
dbg() << "Decoded favicon, " << bitmap->size();
|
||||
if (auto* page = frame().page())
|
||||
page->client().page_did_change_favicon(*bitmap);
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FrameLoader::load(const URL& url, Type type)
|
||||
{
|
||||
dbg() << "FrameLoader::load: " << url;
|
||||
|
||||
if (!url.is_valid()) {
|
||||
load_error_page(url, "Invalid URL");
|
||||
return false;
|
||||
}
|
||||
|
||||
LoadRequest request;
|
||||
request.set_url(url);
|
||||
|
||||
return load(request, type);
|
||||
}
|
||||
|
||||
void FrameLoader::load_html(const StringView& html, const URL& url)
|
||||
{
|
||||
auto document = DOM::Document::create(url);
|
||||
HTML::HTMLDocumentParser parser(document, html, "utf-8");
|
||||
parser.run(url);
|
||||
frame().set_document(&parser.document());
|
||||
}
|
||||
|
||||
// FIXME: Use an actual templating engine (our own one when it's built, preferably
|
||||
// with a way to check these usages at compile time)
|
||||
|
||||
void FrameLoader::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, auto&) {
|
||||
ASSERT(!data.is_null());
|
||||
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
|
||||
auto html = String::format(
|
||||
String::copy(data).characters(),
|
||||
escape_html_entities(failed_url.to_string()).characters(),
|
||||
escape_html_entities(error).characters());
|
||||
#pragma GCC diagnostic pop
|
||||
auto document = HTML::parse_html_document(html, failed_url, "utf-8");
|
||||
ASSERT(document);
|
||||
frame().set_document(document);
|
||||
},
|
||||
[](auto error) {
|
||||
dbg() << "Failed to load error page: " << error;
|
||||
ASSERT_NOT_REACHED();
|
||||
});
|
||||
}
|
||||
|
||||
void FrameLoader::resource_did_load()
|
||||
{
|
||||
auto url = resource()->url();
|
||||
|
||||
if (!resource()->has_encoded_data()) {
|
||||
load_error_page(url, "No data");
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: Also check HTTP status code before redirecting
|
||||
auto location = resource()->response_headers().get("Location");
|
||||
if (location.has_value()) {
|
||||
load(url.complete_url(location.value()), FrameLoader::Type::Navigation);
|
||||
return;
|
||||
}
|
||||
|
||||
dbgln("I believe this content has MIME type '{}', , encoding '{}'", resource()->mime_type(), resource()->encoding());
|
||||
|
||||
auto document = DOM::Document::create();
|
||||
document->set_url(url);
|
||||
document->set_encoding(resource()->encoding());
|
||||
document->set_content_type(resource()->mime_type());
|
||||
|
||||
frame().set_document(document);
|
||||
|
||||
if (!parse_document(*document, resource()->encoded_data())) {
|
||||
load_error_page(url, "Failed to parse content.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!url.fragment().is_empty())
|
||||
frame().scroll_to_anchor(url.fragment());
|
||||
|
||||
if (auto* host_element = frame().host_element()) {
|
||||
// FIXME: Perhaps in the future we'll have a better common base class for <frame> and <iframe>
|
||||
ASSERT(is<HTML::HTMLIFrameElement>(*host_element));
|
||||
downcast<HTML::HTMLIFrameElement>(*host_element).content_frame_did_load({});
|
||||
}
|
||||
|
||||
if (auto* page = frame().page())
|
||||
page->client().page_did_finish_loading(url);
|
||||
}
|
||||
|
||||
void FrameLoader::resource_did_fail()
|
||||
{
|
||||
load_error_page(resource()->url(), resource()->error());
|
||||
}
|
||||
|
||||
}
|
66
Userland/Libraries/LibWeb/Loader/FrameLoader.h
Normal file
66
Userland/Libraries/LibWeb/Loader/FrameLoader.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Forward.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
#include <LibWeb/Loader/Resource.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
class FrameLoader final
|
||||
: public ResourceClient {
|
||||
public:
|
||||
enum class Type {
|
||||
Navigation,
|
||||
Reload,
|
||||
IFrame,
|
||||
};
|
||||
|
||||
explicit FrameLoader(Frame&);
|
||||
~FrameLoader();
|
||||
|
||||
bool load(const URL&, Type);
|
||||
bool load(const LoadRequest&, Type);
|
||||
|
||||
void load_html(const StringView&, const URL&);
|
||||
|
||||
Frame& frame() { return m_frame; }
|
||||
const Frame& frame() const { return m_frame; }
|
||||
|
||||
private:
|
||||
// ^ResourceClient
|
||||
virtual void resource_did_load() override;
|
||||
virtual void resource_did_fail() override;
|
||||
|
||||
void load_error_page(const URL& failed_url, const String& error_message);
|
||||
bool parse_document(DOM::Document&, const ByteBuffer& data);
|
||||
|
||||
Frame& m_frame;
|
||||
};
|
||||
|
||||
}
|
164
Userland/Libraries/LibWeb/Loader/ImageLoader.cpp
Normal file
164
Userland/Libraries/LibWeb/Loader/ImageLoader.cpp
Normal file
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibCore/Timer.h>
|
||||
#include <LibGfx/Bitmap.h>
|
||||
#include <LibGfx/ImageDecoder.h>
|
||||
#include <LibWeb/Loader/ImageLoader.h>
|
||||
#include <LibWeb/Loader/ResourceLoader.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
ImageLoader::ImageLoader()
|
||||
: m_timer(Core::Timer::construct())
|
||||
{
|
||||
}
|
||||
|
||||
void ImageLoader::load(const URL& url)
|
||||
{
|
||||
m_loading_state = LoadingState::Loading;
|
||||
LoadRequest request;
|
||||
request.set_url(url);
|
||||
set_resource(ResourceLoader::the().load_resource(Resource::Type::Image, request));
|
||||
}
|
||||
|
||||
void ImageLoader::set_visible_in_viewport(bool visible_in_viewport) const
|
||||
{
|
||||
if (m_visible_in_viewport == visible_in_viewport)
|
||||
return;
|
||||
m_visible_in_viewport = visible_in_viewport;
|
||||
|
||||
// FIXME: Don't update volatility every time. If we're here, we're probably scanning through
|
||||
// the whole document, updating "is visible in viewport" flags, and this could lead
|
||||
// to the same bitmap being marked volatile back and forth unnecessarily.
|
||||
if (resource())
|
||||
const_cast<ImageResource*>(resource())->update_volatility();
|
||||
}
|
||||
|
||||
void ImageLoader::resource_did_load()
|
||||
{
|
||||
ASSERT(resource());
|
||||
|
||||
if (!resource()->mime_type().starts_with("image/")) {
|
||||
m_loading_state = LoadingState::Failed;
|
||||
if (on_fail)
|
||||
on_fail();
|
||||
return;
|
||||
}
|
||||
|
||||
m_loading_state = LoadingState::Loaded;
|
||||
|
||||
#ifdef IMAGE_LOADER_DEBUG
|
||||
if (!resource()->has_encoded_data()) {
|
||||
dbg() << "ImageLoader: Resource did load, no encoded data. URL: " << resource()->url();
|
||||
} else {
|
||||
dbg() << "ImageLoader: Resource did load, has encoded data. URL: " << resource()->url();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (resource()->should_decode_in_process()) {
|
||||
auto& decoder = resource()->ensure_decoder();
|
||||
|
||||
if (decoder.is_animated() && decoder.frame_count() > 1) {
|
||||
const auto& first_frame = decoder.frame(0);
|
||||
m_timer->set_interval(first_frame.duration);
|
||||
m_timer->on_timeout = [this] { animate(); };
|
||||
m_timer->start();
|
||||
}
|
||||
}
|
||||
|
||||
if (on_load)
|
||||
on_load();
|
||||
}
|
||||
|
||||
void ImageLoader::animate()
|
||||
{
|
||||
if (!m_visible_in_viewport)
|
||||
return;
|
||||
|
||||
auto& decoder = resource()->ensure_decoder();
|
||||
|
||||
m_current_frame_index = (m_current_frame_index + 1) % decoder.frame_count();
|
||||
const auto& current_frame = decoder.frame(m_current_frame_index);
|
||||
|
||||
if (current_frame.duration != m_timer->interval()) {
|
||||
m_timer->restart(current_frame.duration);
|
||||
}
|
||||
|
||||
if (m_current_frame_index == decoder.frame_count() - 1) {
|
||||
++m_loops_completed;
|
||||
if (m_loops_completed > 0 && m_loops_completed == decoder.loop_count()) {
|
||||
m_timer->stop();
|
||||
}
|
||||
}
|
||||
|
||||
if (on_animate)
|
||||
on_animate();
|
||||
}
|
||||
|
||||
void ImageLoader::resource_did_fail()
|
||||
{
|
||||
dbg() << "ImageLoader: Resource did fail. URL: " << resource()->url();
|
||||
m_loading_state = LoadingState::Failed;
|
||||
if (on_fail)
|
||||
on_fail();
|
||||
}
|
||||
|
||||
bool ImageLoader::has_image() const
|
||||
{
|
||||
if (!resource())
|
||||
return false;
|
||||
if (resource()->should_decode_in_process())
|
||||
return const_cast<ImageResource*>(resource())->ensure_decoder().bitmap();
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned ImageLoader::width() const
|
||||
{
|
||||
if (!resource())
|
||||
return 0;
|
||||
if (resource()->should_decode_in_process())
|
||||
return const_cast<ImageResource*>(resource())->ensure_decoder().width();
|
||||
return bitmap() ? bitmap()->width() : 0;
|
||||
}
|
||||
|
||||
unsigned ImageLoader::height() const
|
||||
{
|
||||
if (!resource())
|
||||
return 0;
|
||||
if (resource()->should_decode_in_process())
|
||||
return const_cast<ImageResource*>(resource())->ensure_decoder().height();
|
||||
return bitmap() ? bitmap()->height() : 0;
|
||||
}
|
||||
|
||||
const Gfx::Bitmap* ImageLoader::bitmap() const
|
||||
{
|
||||
if (!resource())
|
||||
return nullptr;
|
||||
return resource()->bitmap(m_current_frame_index);
|
||||
}
|
||||
|
||||
}
|
79
Userland/Libraries/LibWeb/Loader/ImageLoader.h
Normal file
79
Userland/Libraries/LibWeb/Loader/ImageLoader.h
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Function.h>
|
||||
#include <LibCore/Timer.h>
|
||||
#include <LibWeb/Loader/ImageResource.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
class ImageLoader : public ImageResourceClient {
|
||||
public:
|
||||
ImageLoader();
|
||||
|
||||
void load(const URL&);
|
||||
|
||||
const Gfx::Bitmap* bitmap() const;
|
||||
|
||||
bool has_image() const;
|
||||
|
||||
bool has_loaded_or_failed() const { return m_loading_state != LoadingState::Loading; }
|
||||
|
||||
void set_visible_in_viewport(bool) const;
|
||||
|
||||
unsigned width() const;
|
||||
unsigned height() const;
|
||||
|
||||
Function<void()> on_load;
|
||||
Function<void()> on_fail;
|
||||
Function<void()> on_animate;
|
||||
|
||||
private:
|
||||
// ^ImageResourceClient
|
||||
virtual void resource_did_load() override;
|
||||
virtual void resource_did_fail() override;
|
||||
virtual bool is_visible_in_viewport() const override { return m_visible_in_viewport; }
|
||||
|
||||
void animate();
|
||||
|
||||
enum class LoadingState {
|
||||
None,
|
||||
Loading,
|
||||
Loaded,
|
||||
Failed,
|
||||
};
|
||||
|
||||
mutable bool m_visible_in_viewport { false };
|
||||
|
||||
size_t m_current_frame_index { 0 };
|
||||
size_t m_loops_completed { 0 };
|
||||
LoadingState m_loading_state { LoadingState::Loading };
|
||||
NonnullRefPtr<Core::Timer> m_timer;
|
||||
};
|
||||
|
||||
}
|
103
Userland/Libraries/LibWeb/Loader/ImageResource.cpp
Normal file
103
Userland/Libraries/LibWeb/Loader/ImageResource.cpp
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <AK/Function.h>
|
||||
#include <LibGfx/Bitmap.h>
|
||||
#include <LibGfx/ImageDecoder.h>
|
||||
#include <LibImageDecoderClient/Client.h>
|
||||
#include <LibWeb/Loader/ImageResource.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
ImageResource::ImageResource(const LoadRequest& request)
|
||||
: Resource(Type::Image, request)
|
||||
{
|
||||
}
|
||||
|
||||
ImageResource::~ImageResource()
|
||||
{
|
||||
}
|
||||
|
||||
bool ImageResource::should_decode_in_process() const
|
||||
{
|
||||
return mime_type() == "image/gif";
|
||||
}
|
||||
|
||||
Gfx::ImageDecoder& ImageResource::ensure_decoder()
|
||||
{
|
||||
if (!m_decoder)
|
||||
m_decoder = Gfx::ImageDecoder::create(encoded_data());
|
||||
return *m_decoder;
|
||||
}
|
||||
|
||||
const Gfx::Bitmap* ImageResource::bitmap(size_t frame_index) const
|
||||
{
|
||||
if (!has_encoded_data())
|
||||
return nullptr;
|
||||
|
||||
if (should_decode_in_process()) {
|
||||
if (!m_decoder)
|
||||
return nullptr;
|
||||
if (m_decoder->is_animated())
|
||||
m_decoded_image = m_decoder->frame(frame_index).image;
|
||||
else
|
||||
m_decoded_image = m_decoder->bitmap();
|
||||
} else if (!m_decoded_image && !m_has_attempted_decode) {
|
||||
auto image_decoder_client = ImageDecoderClient::Client::construct();
|
||||
m_decoded_image = image_decoder_client->decode_image(encoded_data());
|
||||
m_has_attempted_decode = true;
|
||||
}
|
||||
return m_decoded_image;
|
||||
}
|
||||
|
||||
void ImageResource::update_volatility()
|
||||
{
|
||||
if (!m_decoder)
|
||||
return;
|
||||
|
||||
bool visible_in_viewport = false;
|
||||
for_each_client([&](auto& client) {
|
||||
if (static_cast<const ImageResourceClient&>(client).is_visible_in_viewport())
|
||||
visible_in_viewport = true;
|
||||
});
|
||||
|
||||
if (!visible_in_viewport) {
|
||||
m_decoder->set_volatile();
|
||||
return;
|
||||
}
|
||||
|
||||
bool still_has_decoded_image = m_decoder->set_nonvolatile();
|
||||
if (still_has_decoded_image)
|
||||
return;
|
||||
|
||||
m_decoder = nullptr;
|
||||
}
|
||||
|
||||
ImageResourceClient::~ImageResourceClient()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
66
Userland/Libraries/LibWeb/Loader/ImageResource.h
Normal file
66
Userland/Libraries/LibWeb/Loader/ImageResource.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/Loader/Resource.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
class ImageResource final : public Resource {
|
||||
friend class Resource;
|
||||
|
||||
public:
|
||||
virtual ~ImageResource() override;
|
||||
Gfx::ImageDecoder& ensure_decoder();
|
||||
const Gfx::Bitmap* bitmap(size_t frame_index = 0) const;
|
||||
|
||||
bool should_decode_in_process() const;
|
||||
|
||||
void update_volatility();
|
||||
|
||||
private:
|
||||
explicit ImageResource(const LoadRequest&);
|
||||
RefPtr<Gfx::ImageDecoder> m_decoder;
|
||||
mutable RefPtr<Gfx::Bitmap> m_decoded_image;
|
||||
mutable bool m_has_attempted_decode { false };
|
||||
};
|
||||
|
||||
class ImageResourceClient : public ResourceClient {
|
||||
public:
|
||||
virtual ~ImageResourceClient();
|
||||
|
||||
virtual bool is_visible_in_viewport() const { return false; }
|
||||
|
||||
protected:
|
||||
ImageResource* resource() { return static_cast<ImageResource*>(ResourceClient::resource()); }
|
||||
const ImageResource* resource() const { return static_cast<const ImageResource*>(ResourceClient::resource()); }
|
||||
|
||||
private:
|
||||
virtual Resource::Type client_type() const override { return Resource::Type::Image; }
|
||||
};
|
||||
|
||||
}
|
94
Userland/Libraries/LibWeb/Loader/LoadRequest.h
Normal file
94
Userland/Libraries/LibWeb/Loader/LoadRequest.h
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/ByteBuffer.h>
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/URL.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
class LoadRequest {
|
||||
public:
|
||||
LoadRequest()
|
||||
{
|
||||
}
|
||||
|
||||
bool is_valid() const { return m_url.is_valid(); }
|
||||
|
||||
const URL& url() const { return m_url; }
|
||||
void set_url(const URL& url) { m_url = url; }
|
||||
|
||||
const String& method() const { return m_method; }
|
||||
void set_method(const String& method) { m_method = method; }
|
||||
|
||||
const ByteBuffer& body() const { return m_body; }
|
||||
void set_body(const ByteBuffer& body) { m_body = body; }
|
||||
|
||||
unsigned hash() const
|
||||
{
|
||||
// FIXME: Include headers in the hash as well
|
||||
return pair_int_hash(pair_int_hash(m_url.to_string().hash(), m_method.hash()), string_hash((const char*)m_body.data(), m_body.size()));
|
||||
}
|
||||
|
||||
bool operator==(const LoadRequest& other) const
|
||||
{
|
||||
if (m_headers.size() != other.m_headers.size())
|
||||
return false;
|
||||
for (auto& it : m_headers) {
|
||||
auto jt = other.m_headers.find(it.key);
|
||||
if (jt == other.m_headers.end())
|
||||
return false;
|
||||
if (it.value != jt->value)
|
||||
return false;
|
||||
}
|
||||
return m_url == other.m_url && m_method == other.m_method && m_body == other.m_body;
|
||||
}
|
||||
|
||||
void set_header(const String& name, const String& value) { m_headers.set(name, value); }
|
||||
String header(const String& name) const { return m_headers.get(name).value_or({}); }
|
||||
|
||||
const HashMap<String, String>& headers() const { return m_headers; }
|
||||
|
||||
private:
|
||||
URL m_url;
|
||||
String m_method { "GET" };
|
||||
HashMap<String, String> m_headers;
|
||||
ByteBuffer m_body;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace AK {
|
||||
|
||||
template<>
|
||||
struct Traits<Web::LoadRequest> : public GenericTraits<Web::LoadRequest> {
|
||||
static unsigned hash(const Web::LoadRequest& request) { return request.hash(); }
|
||||
};
|
||||
|
||||
}
|
168
Userland/Libraries/LibWeb/Loader/Resource.cpp
Normal file
168
Userland/Libraries/LibWeb/Loader/Resource.cpp
Normal file
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <AK/Function.h>
|
||||
#include <LibCore/MimeData.h>
|
||||
#include <LibWeb/HTML/HTMLImageElement.h>
|
||||
#include <LibWeb/Loader/Resource.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
NonnullRefPtr<Resource> Resource::create(Badge<ResourceLoader>, Type type, const LoadRequest& request)
|
||||
{
|
||||
if (type == Type::Image)
|
||||
return adopt(*new ImageResource(request));
|
||||
return adopt(*new Resource(type, request));
|
||||
}
|
||||
|
||||
Resource::Resource(Type type, const LoadRequest& request)
|
||||
: m_request(request)
|
||||
, m_type(type)
|
||||
{
|
||||
}
|
||||
|
||||
Resource::~Resource()
|
||||
{
|
||||
}
|
||||
|
||||
void Resource::for_each_client(Function<void(ResourceClient&)> callback)
|
||||
{
|
||||
Vector<WeakPtr<ResourceClient>, 16> clients_copy;
|
||||
clients_copy.ensure_capacity(m_clients.size());
|
||||
for (auto* client : m_clients)
|
||||
clients_copy.append(client->make_weak_ptr());
|
||||
for (auto client : clients_copy) {
|
||||
if (client)
|
||||
callback(*client);
|
||||
}
|
||||
}
|
||||
|
||||
static String encoding_from_content_type(const String& content_type)
|
||||
{
|
||||
auto offset = content_type.index_of("charset=");
|
||||
if (offset.has_value()) {
|
||||
auto encoding = content_type.substring(offset.value() + 8, content_type.length() - offset.value() - 8).to_lowercase();
|
||||
if (encoding.length() >= 2 && encoding.starts_with('"') && encoding.ends_with('"'))
|
||||
return encoding.substring(1, encoding.length() - 2);
|
||||
if (encoding.length() >= 2 && encoding.starts_with('\'') && encoding.ends_with('\''))
|
||||
return encoding.substring(1, encoding.length() - 2);
|
||||
return encoding;
|
||||
}
|
||||
|
||||
return "utf-8";
|
||||
}
|
||||
|
||||
static String mime_type_from_content_type(const String& content_type)
|
||||
{
|
||||
auto offset = content_type.index_of(";");
|
||||
if (offset.has_value())
|
||||
return content_type.substring(0, offset.value()).to_lowercase();
|
||||
|
||||
return content_type;
|
||||
}
|
||||
|
||||
void Resource::did_load(Badge<ResourceLoader>, ReadonlyBytes data, const HashMap<String, String, CaseInsensitiveStringTraits>& headers)
|
||||
{
|
||||
ASSERT(!m_loaded);
|
||||
m_encoded_data = ByteBuffer::copy(data);
|
||||
m_response_headers = headers;
|
||||
m_loaded = true;
|
||||
|
||||
auto content_type = headers.get("Content-Type");
|
||||
if (content_type.has_value()) {
|
||||
#ifdef RESOURCE_DEBUG
|
||||
dbgln("Content-Type header: '{}'", content_type.value());
|
||||
#endif
|
||||
m_encoding = encoding_from_content_type(content_type.value());
|
||||
m_mime_type = mime_type_from_content_type(content_type.value());
|
||||
} else if (url().protocol() == "data" && !url().data_mime_type().is_empty()) {
|
||||
#ifdef RESOURCE_DEBUG
|
||||
dbg() << "This is a data URL with mime-type _" << url().data_mime_type() << "_";
|
||||
#endif
|
||||
m_encoding = "utf-8"; // FIXME: This doesn't seem nice.
|
||||
m_mime_type = url().data_mime_type();
|
||||
} else {
|
||||
#ifdef RESOURCE_DEBUG
|
||||
dbgln("No Content-Type header to go on! Guessing based on filename...");
|
||||
#endif
|
||||
m_encoding = "utf-8"; // FIXME: This doesn't seem nice.
|
||||
m_mime_type = Core::guess_mime_type_based_on_filename(url().path());
|
||||
}
|
||||
|
||||
for_each_client([](auto& client) {
|
||||
client.resource_did_load();
|
||||
});
|
||||
}
|
||||
|
||||
void Resource::did_fail(Badge<ResourceLoader>, const String& error)
|
||||
{
|
||||
m_error = error;
|
||||
m_failed = true;
|
||||
|
||||
for_each_client([](auto& client) {
|
||||
client.resource_did_fail();
|
||||
});
|
||||
}
|
||||
|
||||
void Resource::register_client(Badge<ResourceClient>, ResourceClient& client)
|
||||
{
|
||||
ASSERT(!m_clients.contains(&client));
|
||||
m_clients.set(&client);
|
||||
}
|
||||
|
||||
void Resource::unregister_client(Badge<ResourceClient>, ResourceClient& client)
|
||||
{
|
||||
ASSERT(m_clients.contains(&client));
|
||||
m_clients.remove(&client);
|
||||
}
|
||||
|
||||
void ResourceClient::set_resource(Resource* resource)
|
||||
{
|
||||
if (m_resource)
|
||||
m_resource->unregister_client({}, *this);
|
||||
m_resource = resource;
|
||||
if (m_resource) {
|
||||
ASSERT(resource->type() == client_type());
|
||||
|
||||
m_resource->register_client({}, *this);
|
||||
|
||||
// Make sure that reused resources also have their load callback fired.
|
||||
if (resource->is_loaded())
|
||||
resource_did_load();
|
||||
|
||||
// Make sure that reused resources also have their fail callback fired.
|
||||
if (resource->is_failed())
|
||||
resource_did_fail();
|
||||
}
|
||||
}
|
||||
|
||||
ResourceClient::~ResourceClient()
|
||||
{
|
||||
if (m_resource)
|
||||
m_resource->unregister_client({}, *this);
|
||||
}
|
||||
|
||||
}
|
117
Userland/Libraries/LibWeb/Loader/Resource.h
Normal file
117
Userland/Libraries/LibWeb/Loader/Resource.h
Normal file
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/ByteBuffer.h>
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/HashTable.h>
|
||||
#include <AK/Noncopyable.h>
|
||||
#include <AK/RefCounted.h>
|
||||
#include <AK/URL.h>
|
||||
#include <AK/WeakPtr.h>
|
||||
#include <AK/Weakable.h>
|
||||
#include <LibGfx/Forward.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
#include <LibWeb/Loader/LoadRequest.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
class ResourceClient;
|
||||
|
||||
class Resource : public RefCounted<Resource> {
|
||||
AK_MAKE_NONCOPYABLE(Resource);
|
||||
AK_MAKE_NONMOVABLE(Resource);
|
||||
|
||||
public:
|
||||
enum class Type {
|
||||
Generic,
|
||||
Image,
|
||||
};
|
||||
|
||||
static NonnullRefPtr<Resource> create(Badge<ResourceLoader>, Type, const LoadRequest&);
|
||||
virtual ~Resource();
|
||||
|
||||
Type type() const { return m_type; }
|
||||
|
||||
bool is_loaded() const { return m_loaded; }
|
||||
|
||||
bool is_failed() const { return m_failed; }
|
||||
const String& error() const { return m_error; }
|
||||
|
||||
bool has_encoded_data() const { return !m_encoded_data.is_null(); }
|
||||
|
||||
const URL& url() const { return m_request.url(); }
|
||||
const ByteBuffer& encoded_data() const { return m_encoded_data; }
|
||||
|
||||
const HashMap<String, String, CaseInsensitiveStringTraits>& response_headers() const { return m_response_headers; }
|
||||
|
||||
void register_client(Badge<ResourceClient>, ResourceClient&);
|
||||
void unregister_client(Badge<ResourceClient>, ResourceClient&);
|
||||
|
||||
const String& encoding() const { return m_encoding; }
|
||||
const String& mime_type() const { return m_mime_type; }
|
||||
|
||||
void for_each_client(Function<void(ResourceClient&)>);
|
||||
|
||||
void did_load(Badge<ResourceLoader>, ReadonlyBytes data, const HashMap<String, String, CaseInsensitiveStringTraits>& headers);
|
||||
void did_fail(Badge<ResourceLoader>, const String& error);
|
||||
|
||||
protected:
|
||||
explicit Resource(Type, const LoadRequest&);
|
||||
|
||||
private:
|
||||
LoadRequest m_request;
|
||||
ByteBuffer m_encoded_data;
|
||||
Type m_type { Type::Generic };
|
||||
bool m_loaded { false };
|
||||
bool m_failed { false };
|
||||
String m_error;
|
||||
String m_encoding;
|
||||
String m_mime_type;
|
||||
HashMap<String, String, CaseInsensitiveStringTraits> m_response_headers;
|
||||
HashTable<ResourceClient*> m_clients;
|
||||
};
|
||||
|
||||
class ResourceClient : public Weakable<ResourceClient> {
|
||||
public:
|
||||
virtual ~ResourceClient();
|
||||
|
||||
virtual void resource_did_load() { }
|
||||
virtual void resource_did_fail() { }
|
||||
|
||||
protected:
|
||||
virtual Resource::Type client_type() const { return Resource::Type::Generic; }
|
||||
|
||||
Resource* resource() { return m_resource; }
|
||||
const Resource* resource() const { return m_resource; }
|
||||
void set_resource(Resource*);
|
||||
|
||||
private:
|
||||
RefPtr<Resource> m_resource;
|
||||
};
|
||||
|
||||
}
|
235
Userland/Libraries/LibWeb/Loader/ResourceLoader.cpp
Normal file
235
Userland/Libraries/LibWeb/Loader/ResourceLoader.cpp
Normal file
|
@ -0,0 +1,235 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <AK/Base64.h>
|
||||
#include <AK/JsonObject.h>
|
||||
#include <AK/SharedBuffer.h>
|
||||
#include <LibCore/EventLoop.h>
|
||||
#include <LibCore/File.h>
|
||||
#include <LibProtocol/Client.h>
|
||||
#include <LibProtocol/Download.h>
|
||||
#include <LibWeb/Loader/ContentFilter.h>
|
||||
#include <LibWeb/Loader/LoadRequest.h>
|
||||
#include <LibWeb/Loader/Resource.h>
|
||||
#include <LibWeb/Loader/ResourceLoader.h>
|
||||
|
||||
//#define CACHE_DEBUG
|
||||
|
||||
namespace Web {
|
||||
|
||||
ResourceLoader& ResourceLoader::the()
|
||||
{
|
||||
static ResourceLoader* s_the;
|
||||
if (!s_the)
|
||||
s_the = &ResourceLoader::construct().leak_ref();
|
||||
return *s_the;
|
||||
}
|
||||
|
||||
ResourceLoader::ResourceLoader()
|
||||
: m_protocol_client(Protocol::Client::construct())
|
||||
, m_user_agent("Mozilla/4.0 (SerenityOS; x86) LibWeb+LibJS (Not KHTML, nor Gecko) LibWeb")
|
||||
{
|
||||
}
|
||||
|
||||
void ResourceLoader::load_sync(const URL& url, Function<void(ReadonlyBytes, const HashMap<String, String, CaseInsensitiveStringTraits>& response_headers)> success_callback, Function<void(const String&)> error_callback)
|
||||
{
|
||||
Core::EventLoop loop;
|
||||
|
||||
load(
|
||||
url,
|
||||
[&](auto data, auto& response_headers) {
|
||||
success_callback(data, response_headers);
|
||||
loop.quit(0);
|
||||
},
|
||||
[&](auto& string) {
|
||||
if (error_callback)
|
||||
error_callback(string);
|
||||
loop.quit(0);
|
||||
});
|
||||
|
||||
loop.exec();
|
||||
}
|
||||
|
||||
static HashMap<LoadRequest, NonnullRefPtr<Resource>> s_resource_cache;
|
||||
|
||||
RefPtr<Resource> ResourceLoader::load_resource(Resource::Type type, const LoadRequest& request)
|
||||
{
|
||||
if (!request.is_valid())
|
||||
return nullptr;
|
||||
|
||||
auto it = s_resource_cache.find(request);
|
||||
if (it != s_resource_cache.end()) {
|
||||
if (it->value->type() != type) {
|
||||
dbg() << "FIXME: Not using cached resource for " << request.url() << " since there's a type mismatch.";
|
||||
} else {
|
||||
#ifdef CACHE_DEBUG
|
||||
dbg() << "Reusing cached resource for: " << request.url();
|
||||
#endif
|
||||
return it->value;
|
||||
}
|
||||
}
|
||||
|
||||
auto resource = Resource::create({}, type, request);
|
||||
|
||||
s_resource_cache.set(request, resource);
|
||||
|
||||
load(
|
||||
request,
|
||||
[=](auto data, auto& headers) {
|
||||
const_cast<Resource&>(*resource).did_load({}, data, headers);
|
||||
},
|
||||
[=](auto& error) {
|
||||
const_cast<Resource&>(*resource).did_fail({}, error);
|
||||
});
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
void ResourceLoader::load(const LoadRequest& request, Function<void(ReadonlyBytes, const HashMap<String, String, CaseInsensitiveStringTraits>& response_headers)> success_callback, Function<void(const String&)> error_callback)
|
||||
{
|
||||
auto& url = request.url();
|
||||
|
||||
if (is_port_blocked(url.port())) {
|
||||
dbg() << "ResourceLoader::load: Error: blocked port " << url.port() << " for URL: " << url;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ContentFilter::the().is_filtered(url)) {
|
||||
dbgln("\033[32;1mResourceLoader::load: URL was filtered! {}\033[0m", url);
|
||||
error_callback("URL was filtered");
|
||||
return;
|
||||
}
|
||||
|
||||
if (url.protocol() == "about") {
|
||||
dbg() << "Loading about: URL " << url;
|
||||
deferred_invoke([success_callback = move(success_callback)](auto&) {
|
||||
success_callback(String::empty().to_byte_buffer(), {});
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (url.protocol() == "data") {
|
||||
dbg() << "ResourceLoader loading a data URL with mime-type: '" << url.data_mime_type() << "', base64=" << url.data_payload_is_base64() << ", payload='" << url.data_payload() << "'";
|
||||
|
||||
ByteBuffer data;
|
||||
if (url.data_payload_is_base64())
|
||||
data = decode_base64(url.data_payload());
|
||||
else
|
||||
data = url.data_payload().to_byte_buffer();
|
||||
|
||||
deferred_invoke([data = move(data), success_callback = move(success_callback)](auto&) {
|
||||
success_callback(data, {});
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
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();
|
||||
if (error_callback)
|
||||
error_callback(f->error_string());
|
||||
return;
|
||||
}
|
||||
|
||||
auto data = f->read_all();
|
||||
deferred_invoke([data = move(data), success_callback = move(success_callback)](auto&) {
|
||||
success_callback(data, {});
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (url.protocol() == "http" || url.protocol() == "https" || url.protocol() == "gemini") {
|
||||
HashMap<String, String> headers;
|
||||
headers.set("User-Agent", m_user_agent);
|
||||
headers.set("Accept-Encoding", "gzip");
|
||||
|
||||
for (auto& it : request.headers()) {
|
||||
headers.set(it.key, it.value);
|
||||
}
|
||||
|
||||
auto download = protocol_client().start_download(request.method(), url.to_string(), headers, request.body());
|
||||
if (!download) {
|
||||
if (error_callback)
|
||||
error_callback("Failed to initiate load");
|
||||
return;
|
||||
}
|
||||
download->on_buffered_download_finish = [this, success_callback = move(success_callback), error_callback = move(error_callback), download](bool success, auto, auto& response_headers, auto status_code, ReadonlyBytes payload) {
|
||||
if (status_code.has_value() && status_code.value() >= 400 && status_code.value() <= 499) {
|
||||
if (error_callback)
|
||||
error_callback(String::formatted("HTTP error ({})", status_code.value()));
|
||||
return;
|
||||
}
|
||||
--m_pending_loads;
|
||||
if (on_load_counter_change)
|
||||
on_load_counter_change();
|
||||
if (!success) {
|
||||
if (error_callback)
|
||||
error_callback("HTTP load failed");
|
||||
return;
|
||||
}
|
||||
deferred_invoke([download](auto&) {
|
||||
// Clear circular reference of `download` captured by copy
|
||||
const_cast<Protocol::Download&>(*download).on_buffered_download_finish = nullptr;
|
||||
});
|
||||
success_callback(payload, response_headers);
|
||||
};
|
||||
download->set_should_buffer_all_input(true);
|
||||
download->on_certificate_requested = []() -> Protocol::Download::CertificateAndKey {
|
||||
return {};
|
||||
};
|
||||
++m_pending_loads;
|
||||
if (on_load_counter_change)
|
||||
on_load_counter_change();
|
||||
return;
|
||||
}
|
||||
|
||||
if (error_callback)
|
||||
error_callback(String::formatted("Protocol not implemented: {}", url.protocol()));
|
||||
}
|
||||
|
||||
void ResourceLoader::load(const URL& url, Function<void(ReadonlyBytes, const HashMap<String, String, CaseInsensitiveStringTraits>& response_headers)> success_callback, Function<void(const String&)> error_callback)
|
||||
{
|
||||
LoadRequest request;
|
||||
request.set_url(url);
|
||||
load(request, move(success_callback), move(error_callback));
|
||||
}
|
||||
|
||||
bool ResourceLoader::is_port_blocked(int port)
|
||||
{
|
||||
int ports[] { 1, 7, 9, 11, 13, 15, 17, 19, 20, 21, 22, 23, 25, 37, 42,
|
||||
43, 53, 77, 79, 87, 95, 101, 102, 103, 104, 109, 110, 111, 113,
|
||||
115, 117, 119, 123, 135, 139, 143, 179, 389, 465, 512, 513, 514,
|
||||
515, 526, 530, 531, 532, 540, 556, 563, 587, 601, 636, 993, 995,
|
||||
2049, 3659, 4045, 6000, 6379, 6665, 6666, 6667, 6668, 6669, 9000 };
|
||||
for (auto blocked_port : ports)
|
||||
if (port == blocked_port)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
69
Userland/Libraries/LibWeb/Loader/ResourceLoader.h
Normal file
69
Userland/Libraries/LibWeb/Loader/ResourceLoader.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Function.h>
|
||||
#include <AK/URL.h>
|
||||
#include <LibCore/Object.h>
|
||||
#include <LibWeb/Loader/Resource.h>
|
||||
|
||||
namespace Protocol {
|
||||
class Client;
|
||||
}
|
||||
|
||||
namespace Web {
|
||||
|
||||
class ResourceLoader : public Core::Object {
|
||||
C_OBJECT(ResourceLoader)
|
||||
public:
|
||||
static ResourceLoader& the();
|
||||
|
||||
RefPtr<Resource> load_resource(Resource::Type, const LoadRequest&);
|
||||
|
||||
void load(const LoadRequest&, Function<void(ReadonlyBytes, const HashMap<String, String, CaseInsensitiveStringTraits>& response_headers)> success_callback, Function<void(const String&)> error_callback = nullptr);
|
||||
void load(const URL&, Function<void(ReadonlyBytes, const HashMap<String, String, CaseInsensitiveStringTraits>& response_headers)> success_callback, Function<void(const String&)> error_callback = nullptr);
|
||||
void load_sync(const URL&, Function<void(ReadonlyBytes, const HashMap<String, String, CaseInsensitiveStringTraits>& response_headers)> success_callback, Function<void(const String&)> error_callback = nullptr);
|
||||
|
||||
Function<void()> on_load_counter_change;
|
||||
|
||||
int pending_loads() const { return m_pending_loads; }
|
||||
|
||||
Protocol::Client& protocol_client() { return *m_protocol_client; }
|
||||
|
||||
const String& user_agent() const { return m_user_agent; }
|
||||
|
||||
private:
|
||||
ResourceLoader();
|
||||
static bool is_port_blocked(int port);
|
||||
|
||||
int m_pending_loads { 0 };
|
||||
|
||||
RefPtr<Protocol::Client> m_protocol_client;
|
||||
String m_user_agent;
|
||||
};
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue