Add support for streaming I/O to webserver request data
Rather than reading request body data in memory and sending it to
remote request handlers over D-Bus, send the data to the handler
over a pipe as the data are coming in.
BUG: 24166746
Change-Id: I53499f9f8ed00a9d02740556616ef9b7ea7cc493
diff --git a/libwebserv/dbus_bindings/org.chromium.WebServer.RequestHandler.dbus-xml b/libwebserv/dbus_bindings/org.chromium.WebServer.RequestHandler.dbus-xml
index 5eab71d..dcf51ea 100644
--- a/libwebserv/dbus_bindings/org.chromium.WebServer.RequestHandler.dbus-xml
+++ b/libwebserv/dbus_bindings/org.chromium.WebServer.RequestHandler.dbus-xml
@@ -39,12 +39,14 @@
- body - Raw unparsed request data. Could be empty for POST requests
that have form data/uploaded files already parsed into
form_fields/files parameters.
+ The data is sent over D-Bus as a file descriptor representing
+ the read end of a pipe.
</tp:docstring>
<arg name="request_info" type="(sssss)" direction="in"/>
<arg name="headers" type="a(ss)" direction="in"/>
<arg name="params" type="a(bss)" direction="in"/>
<arg name="files" type="a(issss)" direction="in"/>
- <arg name="body" type="ay" direction="in"/>
+ <arg name="body" type="h" direction="in"/>
<annotation name="org.chromium.DBus.Method.Kind" value="normal"/>
</method>
</interface>
diff --git a/libwebserv/request.cc b/libwebserv/request.cc
index 7b518a4..93b80c4 100644
--- a/libwebserv/request.cc
+++ b/libwebserv/request.cc
@@ -16,6 +16,7 @@
#include <base/callback.h>
#include <chromeos/http/http_utils.h>
+#include <chromeos/streams/file_stream.h>
#include <libwebserv/protocol_handler.h>
@@ -53,8 +54,9 @@
Request::~Request() {
}
-const std::vector<uint8_t>& Request::GetData() const {
- return raw_data_;
+chromeos::StreamPtr Request::GetDataStream() {
+ return chromeos::FileStream::FromFileDescriptor(
+ raw_data_fd_.GetPlatformFile(), false, nullptr);
}
std::vector<PairOfStrings> Request::GetFormData() const {
diff --git a/libwebserv/request.h b/libwebserv/request.h
index 161dfa8..e655be6 100644
--- a/libwebserv/request.h
+++ b/libwebserv/request.h
@@ -22,6 +22,7 @@
#include <vector>
#include <base/callback_forward.h>
+#include <base/files/file.h>
#include <base/macros.h>
#include <base/memory/ref_counted.h>
#include <chromeos/errors/error.h>
@@ -77,7 +78,10 @@
// pre-parsed by the server (e.g. "application/x-www-form-urlencoded" and
// "multipart/form-data"). If there is no request body, or the data has been
// pre-parsed by the server, the returned stream will be empty.
- const std::vector<uint8_t>& GetData() const;
+ // The stream returned is valid for as long as the Request object itself is
+ // alive. Accessing the stream after the Request object is destroyed will lead
+ // to an undefined behavior (will likely just crash).
+ chromeos::StreamPtr GetDataStream();
// Returns the request path (e.g. "/path/document").
const std::string& GetPath() const { return url_; }
@@ -137,7 +141,7 @@
ProtocolHandler* handler_{nullptr};
std::string url_;
std::string method_;
- std::vector<uint8_t> raw_data_;
+ base::File raw_data_fd_;
bool last_posted_data_was_file_{false};
std::multimap<std::string, std::string> post_data_;
diff --git a/libwebserv/server.cc b/libwebserv/server.cc
index 3ec66a8..a15f7ab 100644
--- a/libwebserv/server.cc
+++ b/libwebserv/server.cc
@@ -37,7 +37,7 @@
const std::vector<std::tuple<bool, std::string, std::string>>& in_params,
const std::vector<std::tuple<int32_t, std::string, std::string,
std::string, std::string>>& in_files,
- const std::vector<uint8_t>& in_body) override;
+ const dbus::FileDescriptor& in_body) override;
private:
Server* server_{nullptr};
@@ -50,9 +50,9 @@
std::string>& in_request_info,
const std::vector<std::tuple<std::string, std::string>>& in_headers,
const std::vector<std::tuple<bool, std::string, std::string>>& in_params,
- const std::vector<std::tuple<int32_t, std::string, std::string,
- std::string, std::string>>& in_files,
- const std::vector<uint8_t>& in_body) {
+ const std::vector<std::tuple<int32_t, std::string, std::string, std::string,
+ std::string>>& in_files,
+ const dbus::FileDescriptor& in_body) {
std::string protocol_handler_id = std::get<0>(in_request_info);
std::string request_handler_id = std::get<1>(in_request_info);
std::string request_id = std::get<2>(in_request_info);
@@ -92,7 +92,8 @@
std::get<4>(tuple)}}); // transfer_encoding
}
- request->raw_data_ = in_body;
+ request->raw_data_fd_ = base::File(dup(in_body.value()));
+ CHECK(request->raw_data_fd_.IsValid());
return protocol_handler->ProcessRequest(protocol_handler_id,
request_handler_id,