1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-20 14:55:08 +00:00

ProtocolServer: Stream the downloaded data if possible

This patchset makes ProtocolServer stream the downloads to its client
(LibProtocol), and as such changes the download API; a possible
download lifecycle could be as such:
notation = client->server:'>', server->client:'<', pipe activity:'*'
```
> StartDownload(GET, url, headers, {})
< Response(0, fd 8)
* {data, 1024b}
< HeadersBecameAvailable(0, response_headers, 200)
< DownloadProgress(0, 4K, 1024)
* {data, 1024b}
* {data, 1024b}
< DownloadProgress(0, 4K, 2048)
* {data, 1024b}
< DownloadProgress(0, 4K, 1024)
< DownloadFinished(0, true, 4K)
```

Since managing the received file descriptor is a pain, LibProtocol
implements `Download::stream_into(OutputStream)`, which can be used to
stream the download into any given output stream (be it a file, or
memory, or writing stuff with a delay, etc.).
Also, as some of the users of this API require all the downloaded data
upfront, LibProtocol also implements `set_should_buffer_all_input()`,
which causes the download instance to buffer all the data until the
download is complete, and to call the `on_buffered_download_finish`
hook.
This commit is contained in:
AnotherTest 2020-12-26 17:14:12 +03:30 committed by Andreas Kling
parent 36d642ee75
commit 4a2da10e38
55 changed files with 528 additions and 235 deletions

View file

@ -53,13 +53,13 @@ ResourceLoader::ResourceLoader()
{
}
void ResourceLoader::load_sync(const URL& url, Function<void(const ByteBuffer&, const HashMap<String, String, CaseInsensitiveStringTraits>& response_headers)> success_callback, Function<void(const String&)> error_callback)
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) {
[&](auto data, auto& response_headers) {
success_callback(data, response_headers);
loop.quit(0);
},
@ -97,7 +97,7 @@ RefPtr<Resource> ResourceLoader::load_resource(Resource::Type type, const LoadRe
load(
request,
[=](auto& data, auto& headers) {
[=](auto data, auto& headers) {
const_cast<Resource&>(*resource).did_load({}, data, headers);
},
[=](auto& error) {
@ -107,7 +107,7 @@ RefPtr<Resource> ResourceLoader::load_resource(Resource::Type type, const LoadRe
return resource;
}
void ResourceLoader::load(const LoadRequest& request, Function<void(const ByteBuffer&, const HashMap<String, String, CaseInsensitiveStringTraits>& response_headers)> success_callback, Function<void(const String&)> error_callback)
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())) {
@ -170,7 +170,12 @@ void ResourceLoader::load(const LoadRequest& request, Function<void(const ByteBu
error_callback("Failed to initiate load");
return;
}
download->on_finish = [this, success_callback = move(success_callback), error_callback = move(error_callback)](bool success, ReadonlyBytes payload, auto, auto& response_headers, auto status_code) {
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::format("HTTP error (%u)", status_code.value()));
return;
}
--m_pending_loads;
if (on_load_counter_change)
on_load_counter_change();
@ -179,13 +184,9 @@ void ResourceLoader::load(const LoadRequest& request, Function<void(const ByteBu
error_callback("HTTP load failed");
return;
}
if (status_code.has_value() && status_code.value() >= 400 && status_code.value() <= 499) {
if (error_callback)
error_callback(String::format("HTTP error (%u)", status_code.value()));
return;
}
success_callback(ByteBuffer::copy(payload.data(), payload.size()), response_headers);
success_callback(payload, response_headers);
};
download->set_should_buffer_all_input(true);
download->on_certificate_requested = []() -> Protocol::Download::CertificateAndKey {
return {};
};
@ -199,7 +200,7 @@ void ResourceLoader::load(const LoadRequest& request, Function<void(const ByteBu
error_callback(String::format("Protocol not implemented: %s", url.protocol().characters()));
}
void ResourceLoader::load(const URL& url, Function<void(const ByteBuffer&, const HashMap<String, String, CaseInsensitiveStringTraits>& response_headers)> success_callback, Function<void(const String&)> error_callback)
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);