LegacyReply::LegacyReply(const Message* message) : _message(std::move(message)) { invariant(message->operation() == opReply); QueryResult::View qr = _message->singleData().view2ptr(); // should be checked by caller. invariant(qr.msgdata().getNetworkOp() == opReply); uassert(ErrorCodes::BadValue, str::stream() << "Got legacy command reply with a bad cursorId field," << " expected a value of 0 but got " << qr.getCursorId(), qr.getCursorId() == 0); uassert(ErrorCodes::BadValue, str::stream() << "Got legacy command reply with a bad nReturned field," << " expected a value of 1 but got " << qr.getNReturned(), qr.getNReturned() == 1); uassert(ErrorCodes::BadValue, str::stream() << "Got legacy command reply with a bad startingFrom field," << " expected a value of 0 but got " << qr.getStartingFrom(), qr.getStartingFrom() == 0); std::tie(_commandReply, _metadata) = uassertStatusOK(rpc::upconvertReplyMetadata(BSONObj(qr.data()))); // Copy the bson array of documents from the message into // a contiguous area of memory owned by _docBuffer so // DocumentRange can be used to iterate over documents auto cursorElem = _commandReply[LegacyReplyBuilder::kCursorTag]; if (cursorElem.eoo()) return; BSONObj cursorObj = cursorElem.Obj(); auto firstBatchElem = cursorObj[LegacyReplyBuilder::kFirstBatchTag]; if (firstBatchElem.eoo()) return; for (BSONObjIterator it(firstBatchElem.Obj()); it.more(); it.next()) { invariant((*it).isABSONObj()); BSONObj doc = (*it).Obj(); doc.appendSelfToBufBuilder(_docBuffer); } const char* dataBegin = _docBuffer.buf(); const char* dataEnd = dataBegin + _docBuffer.len(); _outputDocs = DocumentRange(dataBegin, dataEnd); return; }
CommandReply::CommandReply(const Message* message) : _message(message) { const char* begin = _message->singleData().data(); std::size_t length = _message->singleData().dataLen(); // This check failing would normally be operation fatal, but we expect it to have been // done earlier in the network layer, so we make it an invariant. invariant(length <= MaxMessageSizeBytes); const char* messageEnd = begin + length; ConstDataRangeCursor cur(begin, messageEnd); _commandReply = uassertStatusOK(cur.readAndAdvance<Validated<BSONObj>>()).val; _metadata = uassertStatusOK(cur.readAndAdvance<Validated<BSONObj>>()).val; _outputDocs = DocumentRange(cur.data(), messageEnd); }
Reply::Reply(const Message* message) : _message(message) { char* begin = _message->singleData().data(); std::size_t length = _message->singleData().dataLen(); invariant(length <= MaxMessageSizeBytes); // checked by message_port.cpp char* messageEnd = begin + length; ConstDataRangeCursor cur(begin, messageEnd); // TODO(amidvidy): we don't currently handle BSON validation. // we will eventually have to thread serverGlobalParams.objcheck through here // similarly to DbMessage::nextJsObj uassertStatusOK(cur.readAndAdvance<BSONObj>(&_metadata)); uassertStatusOK(cur.readAndAdvance<BSONObj>(&_commandReply)); _outputDocs = DocumentRange(cur.data(), messageEnd); }