123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289 |
- // Copyright 2020 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "protocol_core.h"
- #include <algorithm>
- #include <cassert>
- #include <string>
- namespace crdtp {
- DeserializerState::DeserializerState(std::vector<uint8_t> bytes)
- : storage_(new std::vector<uint8_t>(std::move(bytes))),
- tokenizer_(span<uint8_t>(storage_->data(), storage_->size())) {}
- DeserializerState::DeserializerState(Storage storage, span<uint8_t> span)
- : storage_(std::move(storage)), tokenizer_(span) {}
- void DeserializerState::RegisterError(Error error) {
- assert(Error::OK != error);
- if (tokenizer_.Status().ok())
- status_ = Status{error, tokenizer_.Status().pos};
- }
- void DeserializerState::RegisterFieldPath(span<char> name) {
- field_path_.push_back(name);
- }
- std::string DeserializerState::ErrorMessage(span<char> message_name) const {
- std::string msg = "Failed to deserialize ";
- msg.append(message_name.begin(), message_name.end());
- for (int field = static_cast<int>(field_path_.size()) - 1; field >= 0;
- --field) {
- msg.append(".");
- msg.append(field_path_[field].begin(), field_path_[field].end());
- }
- Status s = status();
- if (!s.ok())
- msg += " - " + s.ToASCIIString();
- return msg;
- }
- Status DeserializerState::status() const {
- if (!tokenizer_.Status().ok())
- return tokenizer_.Status();
- return status_;
- }
- namespace {
- constexpr int32_t GetMandatoryFieldMask(
- const DeserializerDescriptor::Field* fields,
- size_t count) {
- int32_t mask = 0;
- for (size_t i = 0; i < count; ++i) {
- if (!fields[i].is_optional)
- mask |= (1 << i);
- }
- return mask;
- }
- } // namespace
- DeserializerDescriptor::DeserializerDescriptor(const Field* fields,
- size_t field_count)
- : fields_(fields),
- field_count_(field_count),
- mandatory_field_mask_(GetMandatoryFieldMask(fields, field_count)) {}
- bool DeserializerDescriptor::Deserialize(DeserializerState* state,
- void* obj) const {
- auto* tokenizer = state->tokenizer();
- // As a special compatibility quirk, allow empty objects if
- // no mandatory fields are required.
- if (tokenizer->TokenTag() == cbor::CBORTokenTag::DONE &&
- !mandatory_field_mask_) {
- return true;
- }
- if (tokenizer->TokenTag() == cbor::CBORTokenTag::ENVELOPE)
- tokenizer->EnterEnvelope();
- if (tokenizer->TokenTag() != cbor::CBORTokenTag::MAP_START) {
- state->RegisterError(Error::CBOR_MAP_START_EXPECTED);
- return false;
- }
- tokenizer->Next();
- int32_t seen_mandatory_fields = 0;
- for (; tokenizer->TokenTag() != cbor::CBORTokenTag::STOP; tokenizer->Next()) {
- if (tokenizer->TokenTag() != cbor::CBORTokenTag::STRING8) {
- state->RegisterError(Error::CBOR_INVALID_MAP_KEY);
- return false;
- }
- span<uint8_t> u_key = tokenizer->GetString8();
- span<char> key(reinterpret_cast<const char*>(u_key.data()), u_key.size());
- tokenizer->Next();
- if (!DeserializeField(state, key, &seen_mandatory_fields, obj))
- return false;
- }
- // Only compute mandatory fields once per type.
- int32_t missing_fields = seen_mandatory_fields ^ mandatory_field_mask_;
- if (missing_fields) {
- int32_t idx = 0;
- while ((missing_fields & 1) == 0) {
- missing_fields >>= 1;
- ++idx;
- }
- state->RegisterError(Error::BINDINGS_MANDATORY_FIELD_MISSING);
- state->RegisterFieldPath(fields_[idx].name);
- return false;
- }
- return true;
- }
- bool DeserializerDescriptor::DeserializeField(DeserializerState* state,
- span<char> name,
- int* seen_mandatory_fields,
- void* obj) const {
- // TODO(caseq): consider checking if the sought field is the one
- // after the last deserialized.
- const auto* begin = fields_;
- const auto* end = fields_ + field_count_;
- auto entry = std::lower_bound(
- begin, end, name, [](const Field& field_desc, span<char> field_name) {
- return SpanLessThan(field_desc.name, field_name);
- });
- // Unknown field is not an error -- we may be working against an
- // implementation of a later version of the protocol.
- // TODO(caseq): support unknown arrays and maps not enclosed by an envelope.
- if (entry == end || !SpanEquals(entry->name, name))
- return true;
- if (!entry->deserializer(state, obj)) {
- state->RegisterFieldPath(name);
- return false;
- }
- if (!entry->is_optional)
- *seen_mandatory_fields |= 1 << (entry - begin);
- return true;
- }
- bool ProtocolTypeTraits<bool>::Deserialize(DeserializerState* state,
- bool* value) {
- const auto tag = state->tokenizer()->TokenTag();
- if (tag == cbor::CBORTokenTag::TRUE_VALUE) {
- *value = true;
- return true;
- }
- if (tag == cbor::CBORTokenTag::FALSE_VALUE) {
- *value = false;
- return true;
- }
- state->RegisterError(Error::BINDINGS_BOOL_VALUE_EXPECTED);
- return false;
- }
- void ProtocolTypeTraits<bool>::Serialize(bool value,
- std::vector<uint8_t>* bytes) {
- bytes->push_back(value ? cbor::EncodeTrue() : cbor::EncodeFalse());
- }
- bool ProtocolTypeTraits<int32_t>::Deserialize(DeserializerState* state,
- int32_t* value) {
- if (state->tokenizer()->TokenTag() != cbor::CBORTokenTag::INT32) {
- state->RegisterError(Error::BINDINGS_INT32_VALUE_EXPECTED);
- return false;
- }
- *value = state->tokenizer()->GetInt32();
- return true;
- }
- void ProtocolTypeTraits<int32_t>::Serialize(int32_t value,
- std::vector<uint8_t>* bytes) {
- cbor::EncodeInt32(value, bytes);
- }
- ContainerSerializer::ContainerSerializer(std::vector<uint8_t>* bytes,
- uint8_t tag)
- : bytes_(bytes) {
- envelope_.EncodeStart(bytes_);
- bytes_->push_back(tag);
- }
- void ContainerSerializer::EncodeStop() {
- bytes_->push_back(cbor::EncodeStop());
- envelope_.EncodeStop(bytes_);
- }
- ObjectSerializer::ObjectSerializer()
- : serializer_(&owned_bytes_, cbor::EncodeIndefiniteLengthMapStart()) {}
- ObjectSerializer::~ObjectSerializer() = default;
- std::unique_ptr<Serializable> ObjectSerializer::Finish() {
- serializer_.EncodeStop();
- return Serializable::From(std::move(owned_bytes_));
- }
- bool ProtocolTypeTraits<double>::Deserialize(DeserializerState* state,
- double* value) {
- // Double values that round-trip through JSON may end up getting represented
- // as an int32 (SIGNED, UNSIGNED) on the wire in CBOR. Therefore, we also
- // accept an INT32 here.
- if (state->tokenizer()->TokenTag() == cbor::CBORTokenTag::INT32) {
- *value = state->tokenizer()->GetInt32();
- return true;
- }
- if (state->tokenizer()->TokenTag() != cbor::CBORTokenTag::DOUBLE) {
- state->RegisterError(Error::BINDINGS_DOUBLE_VALUE_EXPECTED);
- return false;
- }
- *value = state->tokenizer()->GetDouble();
- return true;
- }
- void ProtocolTypeTraits<double>::Serialize(double value,
- std::vector<uint8_t>* bytes) {
- cbor::EncodeDouble(value, bytes);
- }
- class IncomingDeferredMessage : public DeferredMessage {
- public:
- // Creates the state from the part of another message.
- // Note storage is opaque and is mostly to retain ownership.
- // It may be null in case caller owns the memory and will dispose
- // of the message synchronously.
- IncomingDeferredMessage(DeserializerState::Storage storage,
- span<uint8_t> span)
- : storage_(storage), span_(span) {}
- private:
- DeserializerState MakeDeserializer() const override {
- return DeserializerState(storage_, span_);
- }
- void AppendSerialized(std::vector<uint8_t>* out) const override {
- out->insert(out->end(), span_.begin(), span_.end());
- }
- DeserializerState::Storage storage_;
- span<uint8_t> span_;
- };
- class OutgoingDeferredMessage : public DeferredMessage {
- public:
- OutgoingDeferredMessage() = default;
- explicit OutgoingDeferredMessage(std::unique_ptr<Serializable> serializable)
- : serializable_(std::move(serializable)) {
- assert(!!serializable_);
- }
- private:
- DeserializerState MakeDeserializer() const override {
- return DeserializerState(serializable_->Serialize());
- }
- void AppendSerialized(std::vector<uint8_t>* out) const override {
- serializable_->AppendSerialized(out);
- }
- std::unique_ptr<Serializable> serializable_;
- };
- // static
- std::unique_ptr<DeferredMessage> DeferredMessage::FromSerializable(
- std::unique_ptr<Serializable> serializeable) {
- return std::make_unique<OutgoingDeferredMessage>(std::move(serializeable));
- }
- // static
- std::unique_ptr<DeferredMessage> DeferredMessage::FromSpan(
- span<uint8_t> bytes) {
- return std::make_unique<IncomingDeferredMessage>(nullptr, bytes);
- }
- bool ProtocolTypeTraits<std::unique_ptr<DeferredMessage>>::Deserialize(
- DeserializerState* state,
- std::unique_ptr<DeferredMessage>* value) {
- if (state->tokenizer()->TokenTag() != cbor::CBORTokenTag::ENVELOPE) {
- state->RegisterError(Error::CBOR_INVALID_ENVELOPE);
- return false;
- }
- *value = std::make_unique<IncomingDeferredMessage>(
- state->storage(), state->tokenizer()->GetEnvelope());
- return true;
- }
- void ProtocolTypeTraits<std::unique_ptr<DeferredMessage>>::Serialize(
- const std::unique_ptr<DeferredMessage>& value,
- std::vector<uint8_t>* bytes) {
- value->AppendSerialized(bytes);
- }
- } // namespace crdtp
|