1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 07:28:11 +00:00

pro: Use Core::Stream for writing contents to the output

We also have to do a little dance with file descriptor numbers, since we
can't just `freopen` a `FILE` struct anymore to redirect to the correct
file.
This commit is contained in:
Tim Schumacher 2023-01-14 13:07:30 +01:00 committed by Jelle Raaijmakers
parent 5320ed0fd6
commit 2313460b3e

View file

@ -102,52 +102,47 @@ private:
bool m_might_be_wrong { false }; bool m_might_be_wrong { false };
}; };
/// Wraps a stream to silently ignore writes when the condition isn't true.
template<typename ConditionT> template<typename ConditionT>
class ConditionalOutputFileStream final : public OutputFileStream { class ConditionalOutputStream final : public Core::Stream::Stream {
public: public:
template<typename... Args> ConditionalOutputStream(ConditionT&& condition, Core::Stream::Handle<Core::Stream::Stream> stream)
ConditionalOutputFileStream(ConditionT&& condition, Args... args) : m_stream(move(stream))
: OutputFileStream(args...)
, m_condition(condition) , m_condition(condition)
{ {
} }
~ConditionalOutputFileStream() virtual ErrorOr<Bytes> read(Bytes) override
{ {
if (!m_condition()) return Error::from_errno(EBADF);
return; }
if (!m_buffer.is_empty()) { virtual ErrorOr<size_t> write(ReadonlyBytes bytes) override
OutputFileStream::write(m_buffer); {
m_buffer.clear(); // Pretend that we wrote the whole buffer if the condition is untrue.
} if (!m_condition())
return bytes.size();
return m_stream->write(bytes);
}
virtual bool is_eof() const override
{
return true;
}
virtual bool is_open() const override
{
return m_stream->is_open();
}
virtual void close() override
{
} }
private: private:
size_t write(ReadonlyBytes bytes) override Core::Stream::Handle<Core::Stream::Stream> m_stream;
{
if (!m_condition()) {
write_to_buffer:;
// FIXME: Propagate errors.
if (m_buffer.try_append(bytes.data(), bytes.size()).is_error())
return 0;
return bytes.size();
}
if (!m_buffer.is_empty()) {
auto size = OutputFileStream::write(m_buffer);
// FIXME: Propagate errors.
m_buffer = MUST(m_buffer.slice(size, m_buffer.size() - size));
}
if (!m_buffer.is_empty())
goto write_to_buffer;
return OutputFileStream::write(bytes);
}
ConditionT m_condition; ConditionT m_condition;
ByteBuffer m_buffer;
}; };
ErrorOr<int> serenity_main(Main::Arguments arguments) ErrorOr<int> serenity_main(Main::Arguments arguments)
@ -210,6 +205,10 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
args_parser.add_positional_argument(url_str, "URL to download from", "url"); args_parser.add_positional_argument(url_str, "URL to download from", "url");
args_parser.parse(arguments); args_parser.parse(arguments);
// If writing to a file was requested, we'll open a new file descriptor with the same number later.
// Until then, we just clone the stdout file descriptor, because we shouldn't be reopening the actual stdout.
int const output_fd = TRY(Core::System::dup(STDOUT_FILENO));
if (!method_override.is_empty()) { if (!method_override.is_empty()) {
method = method_override; method = method_override;
} else if (data) { } else if (data) {
@ -243,7 +242,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
RefPtr<Protocol::Request> request; RefPtr<Protocol::Request> request;
auto protocol_client = TRY(Protocol::RequestClient::try_create()); auto protocol_client = TRY(Protocol::RequestClient::try_create());
auto output_stream = ConditionalOutputFileStream { [&] { return should_save_stream_data; }, stdout }; auto output_stream = ConditionalOutputStream { [&] { return should_save_stream_data; }, TRY(Core::Stream::File::adopt_fd(output_fd, Core::Stream::OpenMode::Write)) };
// https://httpwg.org/specs/rfc9110.html#authentication // https://httpwg.org/specs/rfc9110.html#authentication
auto const has_credentials = !credentials.is_empty(); auto const has_credentials = !credentials.is_empty();
@ -343,8 +342,21 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
} while (Core::File::exists(output_name)); } while (Core::File::exists(output_name));
} }
if (freopen(output_name.characters(), "w", stdout) == nullptr) { int target_file_fd = open(output_name.characters(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
perror("freopen"); if (target_file_fd < 0) {
perror("target file open");
loop.quit(1);
return;
}
if (dup2(target_file_fd, output_fd) < 0) {
perror("target file dup2");
loop.quit(1);
return;
}
if (close(target_file_fd) < 0) {
perror("target file close");
loop.quit(1); loop.quit(1);
return; return;
} }
@ -394,7 +406,5 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
dbgln("started request with id {}", request->id()); dbgln("started request with id {}", request->id());
auto rc = loop.exec(); return loop.exec();
fflush(stdout);
return rc;
} }