From 2568a93b5dd29d2b06d613a4ece502ee696f189a Mon Sep 17 00:00:00 2001 From: AnotherTest Date: Thu, 31 Dec 2020 01:42:44 +0330 Subject: ProtocolServer: Avoid blocking all downloads when client stops reading Fixes #4668. --- Services/ProtocolServer/GeminiProtocol.cpp | 13 ++++++------- Services/ProtocolServer/HttpProtocol.cpp | 12 ++++-------- Services/ProtocolServer/HttpsProtocol.cpp | 12 +++++------- Services/ProtocolServer/Protocol.cpp | 14 ++++++++++++++ Services/ProtocolServer/Protocol.h | 6 ++++++ 5 files changed, 35 insertions(+), 22 deletions(-) (limited to 'Services/ProtocolServer') 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 #include #include +#include namespace ProtocolServer { @@ -45,17 +46,15 @@ OwnPtr 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(fd_pair[1]); + + auto output_stream = make(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 #include #include -#include namespace ProtocolServer { @@ -52,18 +51,15 @@ OwnPtr 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(fd_pair[1]); + auto output_stream = make(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 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(fd_pair[1]); + + auto output_stream = make(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 #include +#include +#include namespace ProtocolServer { @@ -50,4 +52,16 @@ Protocol::~Protocol() ASSERT_NOT_REACHED(); } +Result 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 +#include #include #include @@ -43,6 +44,11 @@ public: protected: explicit Protocol(const String& name); + struct Pipe { + int read_fd { -1 }; + int write_fd { -1 }; + }; + static Result get_pipe_for_download(); private: String m_name; -- cgit v1.2.3