mirror of
https://github.com/RGBCube/serenity
synced 2025-05-25 22:15:06 +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:
parent
36d642ee75
commit
4a2da10e38
55 changed files with 528 additions and 235 deletions
|
@ -24,6 +24,7 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <AK/FileStream.h>
|
||||
#include <AK/SharedBuffer.h>
|
||||
#include <LibProtocol/Client.h>
|
||||
#include <LibProtocol/Download.h>
|
||||
|
@ -47,16 +48,20 @@ bool Client::is_supported_protocol(const String& protocol)
|
|||
return send_sync<Messages::ProtocolServer::IsSupportedProtocol>(protocol)->supported();
|
||||
}
|
||||
|
||||
RefPtr<Download> Client::start_download(const String& method, const String& url, const HashMap<String, String>& request_headers, const ByteBuffer& request_body)
|
||||
template<typename RequestHashMapTraits>
|
||||
RefPtr<Download> Client::start_download(const String& method, const String& url, const HashMap<String, String, RequestHashMapTraits>& request_headers, ReadonlyBytes request_body)
|
||||
{
|
||||
IPC::Dictionary header_dictionary;
|
||||
for (auto& it : request_headers)
|
||||
header_dictionary.add(it.key, it.value);
|
||||
|
||||
i32 download_id = send_sync<Messages::ProtocolServer::StartDownload>(method, url, header_dictionary, String::copy(request_body))->download_id();
|
||||
if (download_id < 0)
|
||||
auto response = send_sync<Messages::ProtocolServer::StartDownload>(method, url, header_dictionary, ByteBuffer::copy(request_body));
|
||||
auto download_id = response->download_id();
|
||||
auto response_fd = response->response_fd().fd();
|
||||
if (download_id < 0 || response_fd < 0)
|
||||
return nullptr;
|
||||
auto download = Download::create_from_id({}, *this, download_id);
|
||||
download->set_download_fd({}, response_fd);
|
||||
m_downloads.set(download_id, download);
|
||||
return download;
|
||||
}
|
||||
|
@ -79,9 +84,8 @@ void Client::handle(const Messages::ProtocolClient::DownloadFinished& message)
|
|||
{
|
||||
RefPtr<Download> download;
|
||||
if ((download = m_downloads.get(message.download_id()).value_or(nullptr))) {
|
||||
download->did_finish({}, message.success(), message.status_code(), message.total_size(), message.shbuf_id(), message.response_headers());
|
||||
download->did_finish({}, message.success(), message.total_size());
|
||||
}
|
||||
send_sync<Messages::ProtocolServer::DisownSharedBuffer>(message.shbuf_id());
|
||||
m_downloads.remove(message.download_id());
|
||||
}
|
||||
|
||||
|
@ -92,6 +96,15 @@ void Client::handle(const Messages::ProtocolClient::DownloadProgress& message)
|
|||
}
|
||||
}
|
||||
|
||||
void Client::handle(const Messages::ProtocolClient::HeadersBecameAvailable& message)
|
||||
{
|
||||
if (auto download = const_cast<Download*>(m_downloads.get(message.download_id()).value_or(nullptr))) {
|
||||
HashMap<String, String, CaseInsensitiveStringTraits> headers;
|
||||
message.response_headers().for_each_entry([&](auto& name, auto& value) { headers.set(name, value); });
|
||||
download->did_receive_headers({}, headers, message.status_code());
|
||||
}
|
||||
}
|
||||
|
||||
OwnPtr<Messages::ProtocolClient::CertificateRequestedResponse> Client::handle(const Messages::ProtocolClient::CertificateRequested& message)
|
||||
{
|
||||
if (auto download = const_cast<Download*>(m_downloads.get(message.download_id()).value_or(nullptr))) {
|
||||
|
@ -102,3 +115,6 @@ OwnPtr<Messages::ProtocolClient::CertificateRequestedResponse> Client::handle(co
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
template RefPtr<Protocol::Download> Protocol::Client::start_download(const String& method, const String& url, const HashMap<String, String>& request_headers, ReadonlyBytes request_body);
|
||||
template RefPtr<Protocol::Download> Protocol::Client::start_download(const String& method, const String& url, const HashMap<String, String, CaseInsensitiveStringTraits>& request_headers, ReadonlyBytes request_body);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue