diff options
author | AnotherTest <ali.mpfard@gmail.com> | 2020-12-31 01:42:44 +0330 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-12-31 16:57:09 +0100 |
commit | 2568a93b5dd29d2b06d613a4ece502ee696f189a (patch) | |
tree | e3d7853f2327a541ef3deec7ffacf1c8cb36353b /Services/ProtocolServer | |
parent | 83fed3fd5de71c0eed7390a3cee3de6627bec3bd (diff) | |
download | serenity-2568a93b5dd29d2b06d613a4ece502ee696f189a.zip |
ProtocolServer: Avoid blocking all downloads when client stops reading
Fixes #4668.
Diffstat (limited to 'Services/ProtocolServer')
-rw-r--r-- | Services/ProtocolServer/GeminiProtocol.cpp | 13 | ||||
-rw-r--r-- | Services/ProtocolServer/HttpProtocol.cpp | 12 | ||||
-rw-r--r-- | Services/ProtocolServer/HttpsProtocol.cpp | 12 | ||||
-rw-r--r-- | Services/ProtocolServer/Protocol.cpp | 14 | ||||
-rw-r--r-- | Services/ProtocolServer/Protocol.h | 6 |
5 files changed, 35 insertions, 22 deletions
diff --git a/Services/ProtocolServer/GeminiProtocol.cpp b/Services/ProtocolServer/GeminiProtocol.cpp index ff4380de7f..8bf748a50c 100644 --- a/Services/ProtocolServer/GeminiProtocol.cpp +++ b/Services/ProtocolServer/GeminiProtocol.cpp @@ -28,6 +28,7 @@ #include <LibGemini/GeminiRequest.h> #include <ProtocolServer/GeminiDownload.h> #include <ProtocolServer/GeminiProtocol.h> +#include <fcntl.h> namespace ProtocolServer { @@ -45,17 +46,15 @@ OwnPtr<Download> GeminiProtocol::start_download(ClientConnection& client, const Gemini::GeminiRequest request; request.set_url(url); - int fd_pair[2] { 0 }; - if (pipe(fd_pair) != 0) { - auto saved_errno = errno; - dbgln("Protocol: pipe() failed: {}", strerror(saved_errno)); + auto pipe_result = get_pipe_for_download(); + if (pipe_result.is_error()) return nullptr; - } - auto output_stream = make<OutputFileStream>(fd_pair[1]); + + auto output_stream = make<OutputFileStream>(pipe_result.value().write_fd); output_stream->make_unbuffered(); auto job = Gemini::GeminiJob::construct(request, *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(); return download; } diff --git a/Services/ProtocolServer/HttpProtocol.cpp b/Services/ProtocolServer/HttpProtocol.cpp index e8c7a3203c..75c7abc1f8 100644 --- a/Services/ProtocolServer/HttpProtocol.cpp +++ b/Services/ProtocolServer/HttpProtocol.cpp @@ -28,7 +28,6 @@ #include <LibHTTP/HttpRequest.h> #include <ProtocolServer/HttpDownload.h> #include <ProtocolServer/HttpProtocol.h> -#include <fcntl.h> namespace ProtocolServer { @@ -52,18 +51,15 @@ OwnPtr<Download> HttpProtocol::start_download(ClientConnection& client, const St request.set_headers(headers); request.set_body(body); - int fd_pair[2] { 0 }; - if (pipe(fd_pair) != 0) { - auto saved_errno = errno; - dbgln("Protocol: pipe() failed: {}", strerror(saved_errno)); + auto pipe_result = get_pipe_for_download(); + if (pipe_result.is_error()) return nullptr; - } - auto output_stream = make<OutputFileStream>(fd_pair[1]); + auto output_stream = make<OutputFileStream>(pipe_result.value().write_fd); output_stream->make_unbuffered(); auto job = HTTP::HttpJob::construct(request, *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(); return download; } diff --git a/Services/ProtocolServer/HttpsProtocol.cpp b/Services/ProtocolServer/HttpsProtocol.cpp index e34ff32422..9979f0e610 100644 --- a/Services/ProtocolServer/HttpsProtocol.cpp +++ b/Services/ProtocolServer/HttpsProtocol.cpp @@ -51,17 +51,15 @@ OwnPtr<Download> HttpsProtocol::start_download(ClientConnection& client, const S request.set_headers(headers); request.set_body(body); - int fd_pair[2] { 0 }; - if (pipe(fd_pair) != 0) { - auto saved_errno = errno; - dbgln("Protocol: pipe() failed: {}", strerror(saved_errno)); + auto pipe_result = get_pipe_for_download(); + if (pipe_result.is_error()) return nullptr; - } - auto output_stream = make<OutputFileStream>(fd_pair[1]); + + auto output_stream = make<OutputFileStream>(pipe_result.value().write_fd); output_stream->make_unbuffered(); auto job = HTTP::HttpsJob::construct(request, *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(); return download; } diff --git a/Services/ProtocolServer/Protocol.cpp b/Services/ProtocolServer/Protocol.cpp index de7d74b269..ee8248dfef 100644 --- a/Services/ProtocolServer/Protocol.cpp +++ b/Services/ProtocolServer/Protocol.cpp @@ -26,6 +26,8 @@ #include <AK/HashMap.h> #include <ProtocolServer/Protocol.h> +#include <fcntl.h> +#include <string.h> namespace ProtocolServer { @@ -50,4 +52,16 @@ Protocol::~Protocol() 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] }; +} + } diff --git a/Services/ProtocolServer/Protocol.h b/Services/ProtocolServer/Protocol.h index 609362f548..89db931afb 100644 --- a/Services/ProtocolServer/Protocol.h +++ b/Services/ProtocolServer/Protocol.h @@ -27,6 +27,7 @@ #pragma once #include <AK/RefPtr.h> +#include <AK/Result.h> #include <AK/URL.h> #include <ProtocolServer/Forward.h> @@ -43,6 +44,11 @@ public: protected: explicit Protocol(const String& name); + struct Pipe { + int read_fd { -1 }; + int write_fd { -1 }; + }; + static Result<Pipe, String> get_pipe_for_download(); private: String m_name; |