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; }
LegacyReply::LegacyReply(const Message* 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); auto status = Validator<BSONObj>::validateLoad(qr.data(), qr.dataLen()); uassert(ErrorCodes::InvalidBSON, str::stream() << "Got legacy command reply with invalid BSON in the metadata field" << causedBy(status), status.isOK()); _commandReply = BSONObj(qr.data()); _commandReply.shareOwnershipWith(message->sharedBuffer()); if (_commandReply.firstElementFieldName() == "$err"_sd) { // Upconvert legacy errors. BSONObjBuilder bob; bob.appendAs(_commandReply.firstElement(), "errmsg"); bob.append("ok", 0.0); if (auto code = _commandReply["code"]) { bob.append(code); } _commandReply = bob.obj(); } return; }