mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-28 18:40:29 +00:00
ProtocolServer: Avoid blocking all downloads when client stops reading
Fixes #4668.
This commit is contained in:
parent
83fed3fd5d
commit
2568a93b5d
Notes:
sideshowbarker
2024-07-19 00:18:27 +09:00
Author: https://github.com/alimpfard Commit: https://github.com/SerenityOS/serenity/commit/2568a93b5dd Pull-request: https://github.com/SerenityOS/serenity/pull/4672 Issue: https://github.com/SerenityOS/serenity/issues/4668 Reviewed-by: https://github.com/awesomekling Reviewed-by: https://github.com/tomuta
7 changed files with 45 additions and 28 deletions
|
@ -165,10 +165,12 @@ void Job::finish_up()
|
||||||
m_state = State::Finished;
|
m_state = State::Finished;
|
||||||
flush_received_buffers();
|
flush_received_buffers();
|
||||||
if (m_received_size != 0) {
|
if (m_received_size != 0) {
|
||||||
// FIXME: What do we do? ignore it?
|
// We have to wait for the client to consume all the downloaded data
|
||||||
// "Transmission failed" is not strictly correct, but let's roll with it for now.
|
// before we can actually call `did_finish`. in a normal flow, this should
|
||||||
|
// never be hit since the client is reading as we are writing, unless there
|
||||||
|
// are too many concurrent downloads going on.
|
||||||
deferred_invoke([this](auto&) {
|
deferred_invoke([this](auto&) {
|
||||||
did_fail(Error::TransmissionFailed);
|
finish_up();
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -376,10 +376,12 @@ void Job::finish_up()
|
||||||
|
|
||||||
flush_received_buffers();
|
flush_received_buffers();
|
||||||
if (m_buffered_size != 0) {
|
if (m_buffered_size != 0) {
|
||||||
// FIXME: What do we do? ignore it?
|
// We have to wait for the client to consume all the downloaded data
|
||||||
// "Transmission failed" is not strictly correct, but let's roll with it for now.
|
// before we can actually call `did_finish`. in a normal flow, this should
|
||||||
|
// never be hit since the client is reading as we are writing, unless there
|
||||||
|
// are too many concurrent downloads going on.
|
||||||
deferred_invoke([this](auto&) {
|
deferred_invoke([this](auto&) {
|
||||||
did_fail(Error::TransmissionFailed);
|
finish_up();
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include <LibGemini/GeminiRequest.h>
|
#include <LibGemini/GeminiRequest.h>
|
||||||
#include <ProtocolServer/GeminiDownload.h>
|
#include <ProtocolServer/GeminiDownload.h>
|
||||||
#include <ProtocolServer/GeminiProtocol.h>
|
#include <ProtocolServer/GeminiProtocol.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
namespace ProtocolServer {
|
namespace ProtocolServer {
|
||||||
|
|
||||||
|
@ -45,17 +46,15 @@ OwnPtr<Download> GeminiProtocol::start_download(ClientConnection& client, const
|
||||||
Gemini::GeminiRequest request;
|
Gemini::GeminiRequest request;
|
||||||
request.set_url(url);
|
request.set_url(url);
|
||||||
|
|
||||||
int fd_pair[2] { 0 };
|
auto pipe_result = get_pipe_for_download();
|
||||||
if (pipe(fd_pair) != 0) {
|
if (pipe_result.is_error())
|
||||||
auto saved_errno = errno;
|
|
||||||
dbgln("Protocol: pipe() failed: {}", strerror(saved_errno));
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
|
||||||
auto output_stream = make<OutputFileStream>(fd_pair[1]);
|
auto output_stream = make<OutputFileStream>(pipe_result.value().write_fd);
|
||||||
output_stream->make_unbuffered();
|
output_stream->make_unbuffered();
|
||||||
auto job = Gemini::GeminiJob::construct(request, *output_stream);
|
auto job = Gemini::GeminiJob::construct(request, *output_stream);
|
||||||
auto download = GeminiDownload::create_with_job({}, client, (Gemini::GeminiJob&)*job, move(output_stream));
|
auto download = GeminiDownload::create_with_job({}, client, (Gemini::GeminiJob&)*job, move(output_stream));
|
||||||
download->set_download_fd(fd_pair[0]);
|
download->set_download_fd(pipe_result.value().read_fd);
|
||||||
job->start();
|
job->start();
|
||||||
return download;
|
return download;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,6 @@
|
||||||
#include <LibHTTP/HttpRequest.h>
|
#include <LibHTTP/HttpRequest.h>
|
||||||
#include <ProtocolServer/HttpDownload.h>
|
#include <ProtocolServer/HttpDownload.h>
|
||||||
#include <ProtocolServer/HttpProtocol.h>
|
#include <ProtocolServer/HttpProtocol.h>
|
||||||
#include <fcntl.h>
|
|
||||||
|
|
||||||
namespace ProtocolServer {
|
namespace ProtocolServer {
|
||||||
|
|
||||||
|
@ -52,18 +51,15 @@ OwnPtr<Download> HttpProtocol::start_download(ClientConnection& client, const St
|
||||||
request.set_headers(headers);
|
request.set_headers(headers);
|
||||||
request.set_body(body);
|
request.set_body(body);
|
||||||
|
|
||||||
int fd_pair[2] { 0 };
|
auto pipe_result = get_pipe_for_download();
|
||||||
if (pipe(fd_pair) != 0) {
|
if (pipe_result.is_error())
|
||||||
auto saved_errno = errno;
|
|
||||||
dbgln("Protocol: pipe() failed: {}", strerror(saved_errno));
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
|
||||||
|
|
||||||
auto output_stream = make<OutputFileStream>(fd_pair[1]);
|
auto output_stream = make<OutputFileStream>(pipe_result.value().write_fd);
|
||||||
output_stream->make_unbuffered();
|
output_stream->make_unbuffered();
|
||||||
auto job = HTTP::HttpJob::construct(request, *output_stream);
|
auto job = HTTP::HttpJob::construct(request, *output_stream);
|
||||||
auto download = HttpDownload::create_with_job({}, client, (HTTP::HttpJob&)*job, move(output_stream));
|
auto download = HttpDownload::create_with_job({}, client, (HTTP::HttpJob&)*job, move(output_stream));
|
||||||
download->set_download_fd(fd_pair[0]);
|
download->set_download_fd(pipe_result.value().read_fd);
|
||||||
job->start();
|
job->start();
|
||||||
return download;
|
return download;
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,17 +51,15 @@ OwnPtr<Download> HttpsProtocol::start_download(ClientConnection& client, const S
|
||||||
request.set_headers(headers);
|
request.set_headers(headers);
|
||||||
request.set_body(body);
|
request.set_body(body);
|
||||||
|
|
||||||
int fd_pair[2] { 0 };
|
auto pipe_result = get_pipe_for_download();
|
||||||
if (pipe(fd_pair) != 0) {
|
if (pipe_result.is_error())
|
||||||
auto saved_errno = errno;
|
|
||||||
dbgln("Protocol: pipe() failed: {}", strerror(saved_errno));
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
|
||||||
auto output_stream = make<OutputFileStream>(fd_pair[1]);
|
auto output_stream = make<OutputFileStream>(pipe_result.value().write_fd);
|
||||||
output_stream->make_unbuffered();
|
output_stream->make_unbuffered();
|
||||||
auto job = HTTP::HttpsJob::construct(request, *output_stream);
|
auto job = HTTP::HttpsJob::construct(request, *output_stream);
|
||||||
auto download = HttpsDownload::create_with_job({}, client, (HTTP::HttpsJob&)*job, move(output_stream));
|
auto download = HttpsDownload::create_with_job({}, client, (HTTP::HttpsJob&)*job, move(output_stream));
|
||||||
download->set_download_fd(fd_pair[0]);
|
download->set_download_fd(pipe_result.value().read_fd);
|
||||||
job->start();
|
job->start();
|
||||||
return download;
|
return download;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
|
|
||||||
#include <AK/HashMap.h>
|
#include <AK/HashMap.h>
|
||||||
#include <ProtocolServer/Protocol.h>
|
#include <ProtocolServer/Protocol.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
namespace ProtocolServer {
|
namespace ProtocolServer {
|
||||||
|
|
||||||
|
@ -50,4 +52,16 @@ Protocol::~Protocol()
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<Protocol::Pipe, String> Protocol::get_pipe_for_download()
|
||||||
|
{
|
||||||
|
int fd_pair[2] { 0 };
|
||||||
|
if (pipe(fd_pair) != 0) {
|
||||||
|
auto saved_errno = errno;
|
||||||
|
dbgln("Protocol: pipe() failed: {}", strerror(saved_errno));
|
||||||
|
return String { strerror(saved_errno) };
|
||||||
|
}
|
||||||
|
fcntl(fd_pair[1], F_SETFL, fcntl(fd_pair[1], F_GETFL) | O_NONBLOCK);
|
||||||
|
return Pipe { fd_pair[0], fd_pair[1] };
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/RefPtr.h>
|
#include <AK/RefPtr.h>
|
||||||
|
#include <AK/Result.h>
|
||||||
#include <AK/URL.h>
|
#include <AK/URL.h>
|
||||||
#include <ProtocolServer/Forward.h>
|
#include <ProtocolServer/Forward.h>
|
||||||
|
|
||||||
|
@ -43,6 +44,11 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit Protocol(const String& name);
|
explicit Protocol(const String& name);
|
||||||
|
struct Pipe {
|
||||||
|
int read_fd { -1 };
|
||||||
|
int write_fd { -1 };
|
||||||
|
};
|
||||||
|
static Result<Pipe, String> get_pipe_for_download();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
String m_name;
|
String m_name;
|
||||||
|
|
Loading…
Reference in a new issue