Skip to content

Commit 2dead92

Browse files
Lubrsigmta
authored andcommitted
RequestServer: Handle client disappearance more gracefully
Without these fixes, RequestServer was likely to crash if the client crashed (e.g. WebContent). This was because there was no error handling for when writing to the client failed. This is particularly an issue because RequestServer has shared instances, so it would then crash every other client of RequestServer. Then, because another RequestServer instance is not currently spun up, it becomes impossible to start any clients that need a RequestServer instance. Recreating a RequestServer should also be handled, but that's not in the scope of this change. We can tell curl that we failed to write data to the client and that the request should be aborted by returning `CURL_WRITEFUNC_ERROR` from the write callback. It is also possible for requests to be destroyed with buffered data, which is normal to happen if the client disappears (i.e. ConnectionFromClient is destroyed) or the request is cancelled by the client. We log a warning in case this is not expected, to assist with debugging related issues.
1 parent 01ede6c commit 2dead92

File tree

1 file changed

+22
-7
lines changed

1 file changed

+22
-7
lines changed

Services/RequestServer/ConnectionFromClient.cpp

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,9 @@ struct ConnectionFromClient::ActiveRequest : public Weakable<ActiveRequest> {
128128
{
129129
write_notifier->set_enabled(false);
130130
write_notifier->on_activation = [this] {
131-
write_queued_bytes_without_blocking();
131+
if (auto maybe_error = write_queued_bytes_without_blocking(); maybe_error.is_error()) {
132+
dbgln("Warning: Failed to write buffered request data (it's likely the client disappeared): {}", maybe_error.error());
133+
}
132134
};
133135
}
134136

@@ -142,24 +144,26 @@ struct ConnectionFromClient::ActiveRequest : public Weakable<ActiveRequest> {
142144
});
143145
}
144146

145-
void write_queued_bytes_without_blocking()
147+
ErrorOr<void> write_queued_bytes_without_blocking()
146148
{
147149
Vector<u8> bytes_to_send;
148150
bytes_to_send.resize(send_buffer.used_buffer_size());
149151
send_buffer.peek_some(bytes_to_send);
150152
auto result = Core::System::write(this->writer_fd, bytes_to_send);
151153
if (result.is_error()) {
152154
if (result.error().code() != EAGAIN) {
153-
VERIFY_NOT_REACHED();
155+
return result.release_error();
154156
}
155157
write_notifier->set_enabled(true);
156-
return;
158+
return {};
157159
}
158160

159161
MUST(send_buffer.discard(result.value()));
160162
write_notifier->set_enabled(!send_buffer.is_eof());
161163
if (send_buffer.is_eof() && done_fetching)
162164
schedule_self_destruction();
165+
166+
return {};
163167
}
164168

165169
void notify_about_fetching_completion()
@@ -171,7 +175,9 @@ struct ConnectionFromClient::ActiveRequest : public Weakable<ActiveRequest> {
171175

172176
~ActiveRequest()
173177
{
174-
VERIFY(send_buffer.is_eof());
178+
if (!send_buffer.is_eof()) {
179+
dbgln("Warning: Request destroyed with buffered data (it's likely that the client disappeared or the request was cancelled)");
180+
}
175181

176182
if (writer_fd > 0)
177183
MUST(Core::System::close(writer_fd));
@@ -235,8 +241,17 @@ size_t ConnectionFromClient::on_data_received(void* buffer, size_t size, size_t
235241

236242
size_t total_size = size * nmemb;
237243
ReadonlyBytes bytes { static_cast<u8 const*>(buffer), total_size };
238-
MUST(request->send_buffer.write_some(bytes));
239-
request->write_queued_bytes_without_blocking();
244+
245+
auto maybe_write_error = [&] -> ErrorOr<void> {
246+
TRY(request->send_buffer.write_some(bytes));
247+
return request->write_queued_bytes_without_blocking();
248+
}();
249+
250+
if (maybe_write_error.is_error()) {
251+
dbgln("ConnectionFromClient::on_data_received: Aborting request because error occurred whilst writing data to the client: {}", maybe_write_error.error());
252+
return CURL_WRITEFUNC_ERROR;
253+
}
254+
240255
request->downloaded_so_far += total_size;
241256
return total_size;
242257
}

0 commit comments

Comments
 (0)