Commit ae225aa7 authored by Kenton Varda's avatar Kenton Varda

Add an easier way to read a message directly into a builder. Requires a copy for…

Add an easier way to read a message directly into a builder. Requires a copy for security/validation.
parent 02157fcb
...@@ -235,6 +235,20 @@ TEST(Serialize, InputStreamEvenSegmentCountLazy) { ...@@ -235,6 +235,20 @@ TEST(Serialize, InputStreamEvenSegmentCountLazy) {
checkTestMessage(reader.getRoot<TestAllTypes>()); checkTestMessage(reader.getRoot<TestAllTypes>());
} }
TEST(Serialize, InputStreamToBuilder) {
TestMessageBuilder builder(1);
initTestMessage(builder.initRoot<TestAllTypes>());
kj::Array<word> serialized = messageToFlatArray(builder);
TestInputStream stream(serialized.asPtr(), false);
MallocMessageBuilder builder2;
readMessageCopy(stream, builder2);
checkTestMessage(builder2.getRoot<TestAllTypes>());
}
class TestOutputStream: public kj::OutputStream { class TestOutputStream: public kj::OutputStream {
public: public:
TestOutputStream() {} TestOutputStream() {}
......
...@@ -236,6 +236,12 @@ kj::ArrayPtr<const word> InputStreamMessageReader::getSegment(uint id) { ...@@ -236,6 +236,12 @@ kj::ArrayPtr<const word> InputStreamMessageReader::getSegment(uint id) {
return segment; return segment;
} }
void readMessageCopy(kj::InputStream& input, MessageBuilder& target,
ReaderOptions options, kj::ArrayPtr<word> scratchSpace) {
InputStreamMessageReader message(input, options, scratchSpace);
target.setRoot(message.getRoot<AnyPointer>());
}
// ------------------------------------------------------------------- // -------------------------------------------------------------------
void writeMessage(kj::OutputStream& output, kj::ArrayPtr<const kj::ArrayPtr<const word>> segments) { void writeMessage(kj::OutputStream& output, kj::ArrayPtr<const kj::ArrayPtr<const word>> segments) {
...@@ -266,6 +272,7 @@ void writeMessage(kj::OutputStream& output, kj::ArrayPtr<const kj::ArrayPtr<cons ...@@ -266,6 +272,7 @@ void writeMessage(kj::OutputStream& output, kj::ArrayPtr<const kj::ArrayPtr<cons
} }
// ======================================================================================= // =======================================================================================
StreamFdMessageReader::~StreamFdMessageReader() noexcept(false) {} StreamFdMessageReader::~StreamFdMessageReader() noexcept(false) {}
void writeMessageToFd(int fd, kj::ArrayPtr<const kj::ArrayPtr<const word>> segments) { void writeMessageToFd(int fd, kj::ArrayPtr<const kj::ArrayPtr<const word>> segments) {
...@@ -273,4 +280,10 @@ void writeMessageToFd(int fd, kj::ArrayPtr<const kj::ArrayPtr<const word>> segme ...@@ -273,4 +280,10 @@ void writeMessageToFd(int fd, kj::ArrayPtr<const kj::ArrayPtr<const word>> segme
writeMessage(stream, segments); writeMessage(stream, segments);
} }
void readMessageCopyFromFd(int fd, MessageBuilder& target,
ReaderOptions options, kj::ArrayPtr<word> scratchSpace) {
kj::FdInputStream stream(fd);
readMessageCopy(stream, target, options, scratchSpace);
}
} // namespace capnp } // namespace capnp
...@@ -96,6 +96,9 @@ size_t computeSerializedSizeInWords(kj::ArrayPtr<const kj::ArrayPtr<const word>> ...@@ -96,6 +96,9 @@ size_t computeSerializedSizeInWords(kj::ArrayPtr<const kj::ArrayPtr<const word>>
// ======================================================================================= // =======================================================================================
class InputStreamMessageReader: public MessageReader { class InputStreamMessageReader: public MessageReader {
// A MessageReader that reads from an abstract kj::InputStream. See also StreamFdMessageReader
// for a subclass specific to file descriptors.
public: public:
InputStreamMessageReader(kj::InputStream& inputStream, InputStreamMessageReader(kj::InputStream& inputStream,
ReaderOptions options = ReaderOptions(), ReaderOptions options = ReaderOptions(),
...@@ -119,6 +122,17 @@ private: ...@@ -119,6 +122,17 @@ private:
kj::UnwindDetector unwindDetector; kj::UnwindDetector unwindDetector;
}; };
void readMessageCopy(kj::InputStream& input, MessageBuilder& target,
ReaderOptions options = ReaderOptions(),
kj::ArrayPtr<word> scratchSpace = nullptr);
// Convenience function which reads a message using `InputStreamMessageReader` then copies the
// content into the target `MessageBuilder`, verifying that the message structure is valid
// (although not necessarily that it matches the desired schema).
//
// (Note that it's also possible to initialize a `MessageBuilder` directly without a copy using one
// of `MessageBuilder`'s constructors. However, this approach skips the validation step and is not
// safe to use on untrusted input. Therefore, we do not provide a convenience method for it.)
void writeMessage(kj::OutputStream& output, MessageBuilder& builder); void writeMessage(kj::OutputStream& output, MessageBuilder& builder);
// Write the message to the given output stream. // Write the message to the given output stream.
...@@ -129,8 +143,7 @@ void writeMessage(kj::OutputStream& output, kj::ArrayPtr<const kj::ArrayPtr<cons ...@@ -129,8 +143,7 @@ void writeMessage(kj::OutputStream& output, kj::ArrayPtr<const kj::ArrayPtr<cons
// Specializations for reading from / writing to file descriptors. // Specializations for reading from / writing to file descriptors.
class StreamFdMessageReader: private kj::FdInputStream, public InputStreamMessageReader { class StreamFdMessageReader: private kj::FdInputStream, public InputStreamMessageReader {
// A MessageReader that reads from a steam-based file descriptor. For seekable file descriptors // A MessageReader that reads from a steam-based file descriptor.
// (e.g. actual disk files), FdFileMessageReader is better, but this will still work.
public: public:
StreamFdMessageReader(int fd, ReaderOptions options = ReaderOptions(), StreamFdMessageReader(int fd, ReaderOptions options = ReaderOptions(),
...@@ -146,6 +159,17 @@ public: ...@@ -146,6 +159,17 @@ public:
~StreamFdMessageReader() noexcept(false); ~StreamFdMessageReader() noexcept(false);
}; };
void readMessageCopyFromFd(int fd, MessageBuilder& target,
ReaderOptions options = ReaderOptions(),
kj::ArrayPtr<word> scratchSpace = nullptr);
// Convenience function which reads a message using `StreamFdMessageReader` then copies the
// content into the target `MessageBuilder`, verifying that the message structure is valid
// (although not necessarily that it matches the desired schema).
//
// (Note that it's also possible to initialize a `MessageBuilder` directly without a copy using one
// of `MessageBuilder`'s constructors. However, this approach skips the validation step and is not
// safe to use on untrusted input. Therefore, we do not provide a convenience method for it.)
void writeMessageToFd(int fd, MessageBuilder& builder); void writeMessageToFd(int fd, MessageBuilder& builder);
// Write the message to the given file descriptor. // Write the message to the given file descriptor.
// //
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment