BSONObj MozJSImplScope::callThreadArgs(const BSONObj& args) { MozJSEntry entry(this); JS::RootedValue function(_context); ValueReader(_context, &function).fromBSONElement(args.firstElement(), true); int argc = args.nFields() - 1; JS::AutoValueVector argv(_context); BSONObjIterator it(args); it.next(); JS::RootedValue value(_context); for (int i = 0; i < argc; ++i) { ValueReader(_context, &value).fromBSONElement(*it, true); argv.append(value); it.next(); } JS::RootedValue out(_context); JS::RootedObject thisv(_context); _checkErrorState(JS::Call(_context, thisv, function, argv, &out), false, true); BSONObjBuilder b; ValueWriter(_context, out).writeThis(&b, "ret"); return b.obj(); }
BSONObj MozJSImplScope::callThreadArgs(const BSONObj& args) { MozJSEntry entry(this); JS::RootedValue function(_context); ValueReader(_context, &function).fromBSONElement(args.firstElement(), args, true); int argc = args.nFields() - 1; JS::AutoValueVector argv(_context); BSONObjIterator it(args); it.next(); JS::RootedValue value(_context); for (int i = 0; i < argc; ++i) { ValueReader(_context, &value).fromBSONElement(*it, args, true); argv.append(value); it.next(); } JS::RootedValue out(_context); JS::RootedObject thisv(_context); _checkErrorState(JS::Call(_context, thisv, function, argv, &out), false, true); JS::RootedObject rout(_context, JS_NewPlainObject(_context)); ObjectWrapper wout(_context, rout); wout.setValue("ret", out); return wout.toBSON(); }
void SessionInfo::Functions::getTxnNumber::call(JSContext* cx, JS::CallArgs args) { auto holder = getHolder(args); invariant(holder); uassert(ErrorCodes::BadValue, "getTxnNumber takes no arguments", args.length() == 0); ValueReader(cx, args.rval()).fromInt64(holder->txnNumber); }
void SessionInfo::Functions::getTxnState::call(JSContext* cx, JS::CallArgs args) { auto holder = getHolder(args); invariant(holder); uassert(ErrorCodes::BadValue, "getTxnState takes no arguments", args.length() == 0); ValueReader(cx, args.rval()).fromStringData(transactionStateName(holder->txnState)); }
void BSONInfo::enumerate(JSContext* cx, JS::HandleObject obj, JS::AutoIdVector& properties) { auto holder = getHolder(obj); if (!holder) return; BSONObjIterator i(holder->_obj); ObjectWrapper o(cx, obj); JS::RootedValue val(cx); JS::RootedId id(cx); while (i.more()) { BSONElement e = i.next(); // TODO: when we get heterogenous set lookup, switch to StringData // rather than involving the temporary string if (holder->_removed.count(e.fieldName())) continue; ValueReader(cx, &val).fromStringData(e.fieldNameStringData()); if (!JS_ValueToId(cx, val, &id)) uasserted(ErrorCodes::JSInterpreterFailure, "Failed to invoke JS_ValueToId"); properties.append(id); } }
void BinDataInfo::Functions::UUID::call(JSContext* cx, JS::CallArgs args) { boost::optional<mongo::UUID> uuid; if (args.length() == 0) { uuid = mongo::UUID::gen(); } else { uassert(ErrorCodes::BadValue, "UUID needs 0 or 1 arguments", args.length() == 1); auto arg = args.get(0); std::string str = ValueWriter(cx, arg).toString(); // For backward compatibility quietly accept and convert 32-character hex strings to // BinData(3, ...) as used for the deprecated UUID v3 BSON type. if (str.length() == 32) { hexToBinData(cx, bdtUUID, arg, args.rval()); return; } uuid = uassertStatusOK(mongo::UUID::parse(str)); }; ConstDataRange cdr = uuid->toCDR(); std::string encoded = mongo::base64::encode(cdr.data(), cdr.length()); JS::AutoValueArray<2> newArgs(cx); newArgs[0].setInt32(newUUID); ValueReader(cx, newArgs[1]).fromStringData(encoded); getScope(cx)->getProto<BinDataInfo>().newInstance(newArgs, args.rval()); }
void OIDInfo::Functions::toString::call(JSContext* cx, JS::CallArgs args) { auto oid = static_cast<OID*>(JS_GetPrivate(args.thisv().toObjectOrNull())); std::string str = str::stream() << "ObjectId(\"" << oid->toString() << "\")"; ValueReader(cx, args.rval()).fromStringData(str); }
void MongoStatusInfo::fromStatus(JSContext* cx, Status status, JS::MutableHandleValue value) { auto scope = getScope(cx); JS::RootedValue undef(cx); undef.setUndefined(); JS::AutoValueArray<1> args(cx); ValueReader(cx, args[0]).fromStringData(status.reason()); JS::RootedObject error(cx); scope->getProto<ErrorInfo>().newInstance(args, &error); JS::RootedObject thisv(cx); scope->getProto<MongoStatusInfo>().newObjectWithProto(&thisv, error); ObjectWrapper thisvObj(cx, thisv); thisvObj.defineProperty( InternedString::code, undef, JSPROP_ENUMERATE | JSPROP_SHARED, smUtils::wrapConstrainedMethod<Functions::code, false, MongoStatusInfo>); thisvObj.defineProperty( InternedString::reason, undef, JSPROP_ENUMERATE | JSPROP_SHARED, smUtils::wrapConstrainedMethod<Functions::reason, false, MongoStatusInfo>); JS_SetPrivate(thisv, scope->trackedNew<Status>(std::move(status))); value.setObjectOrNull(thisv); }
void NativeFunctionInfo::Functions::toString::call(JSContext* cx, JS::CallArgs args) { ObjectWrapper o(cx, args.thisv()); str::stream ss; ss << "[native code]"; ValueReader(cx, args.rval()).fromStringData(ss.operator std::string()); }
void NumberDecimalInfo::Functions::toString::call(JSContext* cx, JS::CallArgs args) { Decimal128 val = NumberDecimalInfo::ToNumberDecimal(cx, args.thisv()); str::stream ss; ss << "NumberDecimal(\"" << val.toString() << "\")"; ValueReader(cx, args.rval()).fromStringData(ss.operator std::string()); }
void NumberIntInfo::Functions::toString::call(JSContext* cx, JS::CallArgs args) { int val = NumberIntInfo::ToNumberInt(cx, args.thisv()); str::stream ss; ss << "NumberInt(" << val << ")"; ValueReader(cx, args.rval()).fromStringData(ss.operator std::string()); }
void TimestampInfo::Functions::toJSON::call(JSContext* cx, JS::CallArgs args) { ObjectWrapper o(cx, args.thisv()); ValueReader(cx, args.rval()) .fromBSON(BSON("$timestamp" << BSON("t" << o.getNumber(InternedString::t) << "i" << o.getNumber(InternedString::i))), nullptr, false); }
void CodeInfo::Functions::toString::call(JSContext* cx, JS::CallArgs args) { ObjectWrapper o(cx, args.thisv()); std::string str = str::stream() << "Code({\"code\":\"" << o.getString(InternedString::code) << "\"," << "\"scope\":" << o.getObject(InternedString::scope) << "\"})"; ValueReader(cx, args.rval()).fromStringData(str); }
void ObjectWrapper::setBSONElement(Key key, const BSONElement& elem, const BSONObj& parent, bool readOnly) { JS::RootedValue value(_context); ValueReader(_context, &value).fromBSONElement(elem, parent, readOnly); setValue(key, value); }
void ValueReader::fromBSONArray(const BSONObj& obj, const BSONObj* parent, bool readOnly) { JS::AutoValueVector avv(_context); BSONForEach(elem, obj) { JS::RootedValue member(_context); ValueReader(_context, &member).fromBSONElement(elem, parent ? *parent : obj, readOnly); if (!avv.append(member)) { uasserted(ErrorCodes::JSInterpreterFailure, "Failed to append to JS array"); } }
std::string parseJSFunctionOrExpression(JSContext* cx, const StringData input) { JS::RootedValue jsStrOut(cx); JS::RootedValue jsStrIn(cx); ValueReader(cx, &jsStrIn).fromStringData(input); ObjectWrapper helpersWrapper(cx, getScope(cx)->getProto<MongoHelpersInfo>().getProto()); helpersWrapper.callMethod("functionExpressionParser", JS::HandleValueArray(jsStrIn), &jsStrOut); return ValueWriter(cx, jsStrOut).toString(); }
void BinDataInfo::Functions::toJSON::call(JSContext* cx, JS::CallArgs args) { ObjectWrapper o(cx, args.thisv()); auto data_str = getEncoded(args.thisv()); std::stringstream ss; ss << std::hex; ss.width(2); ss.fill('0'); ss << o.getNumber(InternedString::type); ValueReader(cx, args.rval()) .fromBSON(BSON("$binary" << *data_str << "$type" << ss.str()), nullptr, false); }
void BinDataInfo::Functions::toString::call(JSContext* cx, JS::CallArgs args) { ObjectWrapper o(cx, args.thisv()); auto str = getEncoded(args.thisv()); str::stream ss; auto binType = o.getNumber(InternedString::type); if (binType == newUUID) { auto decoded = mongo::base64::decode(*str); // If this is in fact a UUID, use a more friendly string representation. if (decoded.length() == mongo::UUID::kNumBytes) { mongo::UUID uuid = mongo::UUID::fromCDR({decoded.data(), decoded.length()}); ss << "UUID(\"" << uuid.toString() << "\")"; ValueReader(cx, args.rval()).fromStringData(ss.operator std::string()); return; } } ss << "BinData(" << binType << ",\"" << *str << "\")"; ValueReader(cx, args.rval()).fromStringData(ss.operator std::string()); }
void BinDataInfo::Functions::hex::call(JSContext* cx, JS::CallArgs args) { auto str = getEncoded(args.thisv()); std::string data = mongo::base64::decode(*str); std::stringstream ss; ss.setf(std::ios_base::hex, std::ios_base::basefield); ss.fill('0'); ss.setf(std::ios_base::right, std::ios_base::adjustfield); for (auto it = data.begin(); it != data.end(); ++it) { unsigned v = (unsigned char)*it; ss << std::setw(2) << v; } ValueReader(cx, args.rval()).fromStringData(ss.str()); }
void CursorInfo::Functions::next::call(JSContext* cx, JS::CallArgs args) { auto cursor = getCursor(args); if (!cursor) { args.rval().setUndefined(); return; } ObjectWrapper o(cx, args.thisv()); BSONObj bson = cursor->next(); bool ro = o.hasField(InternedString::_ro) ? o.getBoolean(InternedString::_ro) : false; // getOwned because cursor->next() gives us unowned bson from an internal // buffer and we need to make a copy ValueReader(cx, args.rval()).fromBSON(bson.getOwned(), nullptr, ro); }
void NativeFunctionInfo::call(JSContext* cx, JS::CallArgs args) { auto holder = getHolder(args); if (!holder) { // Calling the prototype args.rval().setUndefined(); return; } JS::RootedObject robj(cx, JS_NewArrayObject(cx, args)); if (!robj) { uasserted(ErrorCodes::JSInterpreterFailure, "Failed to JS_NewArrayObject"); } BSONObj out = holder->_func(ObjectWrapper(cx, robj).toBSON(), holder->_ctx); ValueReader(cx, args.rval()).fromBSONElement(out.firstElement(), out, false); }
void BSONInfo::resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* resolvedp) { auto holder = getHolder(obj); *resolvedp = false; if (!holder) { return; } IdWrapper idw(cx, id); if (!holder->_readOnly && holder->_removed.count(idw.toString())) { return; } ObjectWrapper o(cx, obj); std::string sname = IdWrapper(cx, id).toString(); if (holder->_obj.hasField(sname)) { auto elem = holder->_obj[sname]; JS::RootedValue vp(cx); ValueReader(cx, &vp).fromBSONElement(elem, holder->_readOnly); o.defineProperty(id, vp, JSPROP_ENUMERATE); if (!holder->_readOnly && (elem.type() == mongo::Object || elem.type() == mongo::Array)) { // if accessing a subobject, we have no way to know if // modifications are being made on writable objects holder->_altered = true; } *resolvedp = true; } }
void ObjectInfo::Functions::invalidForStorage::call(JSContext* cx, JS::CallArgs args) { if (args.length() != 1) uasserted(ErrorCodes::BadValue, "invalidForStorage needs 1 argument"); if (args.get(0).isNull()) { args.rval().setNull(); return; } if (!args.get(0).isObject()) uasserted(ErrorCodes::BadValue, "argument to invalidForStorage has to be an object"); Status validForStorage = ValueWriter(cx, args.get(0)).toBSON().storageValid(true); if (validForStorage.isOK()) { args.rval().setNull(); return; } std::string errmsg = str::stream() << validForStorage.codeString() << ": " << validForStorage.reason(); ValueReader(cx, args.rval()).fromStringData(errmsg); }
int MozJSImplScope::invoke(ScriptingFunction func, const BSONObj* argsObject, const BSONObj* recv, int timeoutMs, bool ignoreReturn, bool readOnlyArgs, bool readOnlyRecv) { MozJSEntry entry(this); auto funcValue = _funcs[func - 1]; JS::RootedValue result(_context); const int nargs = argsObject ? argsObject->nFields() : 0; JS::AutoValueVector args(_context); if (nargs) { BSONObjIterator it(*argsObject); for (int i = 0; i < nargs; i++) { BSONElement next = it.next(); JS::RootedValue value(_context); ValueReader(_context, &value).fromBSONElement(next, *argsObject, readOnlyArgs); args.append(value); } } JS::RootedValue smrecv(_context); if (recv) ValueReader(_context, &smrecv).fromBSON(*recv, nullptr, readOnlyRecv); else smrecv.setObjectOrNull(_global); if (timeoutMs) _engine->getDeadlineMonitor().startDeadline(this, timeoutMs); JS::RootedValue out(_context); JS::RootedObject obj(_context, smrecv.toObjectOrNull()); bool success = JS::Call(_context, obj, funcValue, args, &out); if (timeoutMs) _engine->getDeadlineMonitor().stopDeadline(this); _checkErrorState(success); if (!ignoreReturn) { // must validate the handle because TerminateExecution may have // been thrown after the above checks if (out.isObject() && _nativeFunctionProto.instanceOf(out)) { warning() << "storing native function as return value"; _lastRetIsNativeCode = true; } else { _lastRetIsNativeCode = false; } ObjectWrapper(_context, _global).setValue(kInvokeResult, out); } return 0; }
void OIDInfo::Functions::getter::call(JSContext* cx, JS::CallArgs args) { auto oid = static_cast<OID*>(JS_GetPrivate(args.thisv().toObjectOrNull())); ValueReader(cx, args.rval()).fromStringData(oid->toString()); }
void OIDInfo::Functions::toJSON::call(JSContext* cx, JS::CallArgs args) { auto oid = static_cast<OID*>(JS_GetPrivate(args.thisv().toObjectOrNull())); ValueReader(cx, args.rval()).fromBSON(BSON("$oid" << oid->toString()), nullptr, false); }
void JSThreadInfo::Functions::returnData::call(JSContext* cx, JS::CallArgs args) { ValueReader(cx, args.rval()) .fromBSONElement(getConfig(cx, args)->returnData().firstElement(), true); }
void BinDataInfo::Functions::base64::call(JSContext* cx, JS::CallArgs args) { auto str = getEncoded(args.thisv()); ValueReader(cx, args.rval()).fromStringData(*str); }
void MaxKeyInfo::Functions::toJSON::call(JSContext* cx, JS::CallArgs args) { ValueReader(cx, args.rval()).fromBSON(BSON("$maxKey" << 1), nullptr, false); }
void MaxKeyInfo::Functions::tojson::call(JSContext* cx, JS::CallArgs args) { ValueReader(cx, args.rval()).fromStringData("{ \"$maxKey\" : 1 }"); }