Esempio n. 1
0
void BSONInfo::Functions::bsonWoCompare(JSContext* cx, JS::CallArgs args) {
    if (args.length() != 2)
        uasserted(ErrorCodes::BadValue, "bsonWoCompare needs 2 argument");

    if (!args.get(0).isObject())
        uasserted(ErrorCodes::BadValue, "first argument to bsonWoCompare must be an object");

    if (!args.get(1).isObject())
        uasserted(ErrorCodes::BadValue, "second argument to bsonWoCompare must be an object");

    BSONObj firstObject = ValueWriter(cx, args.get(0)).toBSON();
    BSONObj secondObject = ValueWriter(cx, args.get(1)).toBSON();

    args.rval().setInt32(firstObject.woCompare(secondObject));
}
Esempio n. 2
0
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();
}
Esempio n. 3
0
void MozJSImplScope::_reportError(JSContext* cx, const char* message, JSErrorReport* report) {
    auto scope = getScope(cx);

    if (!JSREPORT_IS_WARNING(report->flags)) {
        str::stream ss;
        ss << message;

        // TODO: something far more elaborate that mimics the stack printing from v8
        JS::RootedValue excn(cx);
        if (JS_GetPendingException(cx, &excn) && excn.isObject()) {
            JS::RootedValue stack(cx);

            ObjectWrapper(cx, excn).getValue("stack", &stack);

            auto str = ValueWriter(cx, stack).toString();

            if (str.empty()) {
                ss << " @" << report->filename << ":" << report->lineno << ":" << report->column
                   << "\n";
            } else {
                ss << " :\n" << str;
            }
        }

        scope->_status = Status(
            JSErrorReportToStatus(cx, report, ErrorCodes::JSInterpreterFailure, message).code(),
            ss);
    }
}
Esempio n. 4
0
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());
}
Esempio n. 5
0
    JSThreadConfig(JSContext* cx, JS::CallArgs args)
        : _started(false), _done(false), _sharedData(new SharedData()) {
        auto scope = getScope(cx);

        uassert(ErrorCodes::JSInterpreterFailure, "need at least one argument", args.length() > 0);
        uassert(ErrorCodes::JSInterpreterFailure,
                "first argument must be a function",
                args.get(0).isObject() && JS_ObjectIsFunction(cx, args.get(0).toObjectOrNull()));

        BSONObjBuilder b;
        for (unsigned i = 0; i < args.length(); ++i) {
            // 10 decimal digits for a 32 bit unsigned, then 1 for the null
            char buf[11];
            std::sprintf(buf, "%i", i);

            ValueWriter(cx, args.get(i)).writeThis(&b, buf);
        }

        _sharedData->_args = b.obj();

        _sharedData->_stack = currentJSStackToString(cx);

        if (!scope->getParentStack().empty()) {
            _sharedData->_stack = _sharedData->_stack + scope->getParentStack();
        }
    }
Esempio n. 6
0
void DBInfo::construct(JSContext* cx, JS::CallArgs args) {
    auto scope = getScope(cx);

    if (args.length() != 2)
        uasserted(ErrorCodes::BadValue, "db constructor requires 2 arguments");

    for (unsigned i = 0; i < args.length(); ++i) {
        uassert(ErrorCodes::BadValue,
                "db initializer called with undefined argument",
                !args.get(i).isUndefined());
    }

    JS::RootedObject thisv(cx);
    scope->getProto<DBInfo>().newObject(&thisv);
    ObjectWrapper o(cx, thisv);

    o.setValue(InternedString::_mongo, args.get(0));
    o.setValue(InternedString::_name, args.get(1));

    std::string dbName = ValueWriter(cx, args.get(1)).toString();

    if (!NamespaceString::validDBName(dbName, NamespaceString::DollarInDbNameBehavior::Allow))
        uasserted(ErrorCodes::BadValue,
                  str::stream() << "[" << dbName << "] is not a valid database name");

    args.rval().setObjectOrNull(thisv);
}
Esempio n. 7
0
void TimestampInfo::construct(JSContext* cx, JS::CallArgs args) {
    auto scope = getScope(cx);

    JS::RootedObject thisv(cx);
    scope->getProto<TimestampInfo>().newObject(&thisv);
    ObjectWrapper o(cx, thisv);

    if (args.length() == 0) {
        o.setNumber(InternedString::t, 0);
        o.setNumber(InternedString::i, 0);
    } else if (args.length() == 2) {
        if (!args.get(0).isNumber())
            uasserted(ErrorCodes::BadValue, "Timestamp time must be a number");
        if (!args.get(1).isNumber())
            uasserted(ErrorCodes::BadValue, "Timestamp increment must be a number");

        int64_t t = ValueWriter(cx, args.get(0)).toInt64();
        int64_t largestVal = int64_t(Timestamp::max().getSecs());
        if (t > largestVal)
            uasserted(ErrorCodes::BadValue,
                      str::stream() << "The first argument must be in seconds; " << t
                                    << " is too large (max " << largestVal << ")");

        o.setValue(InternedString::t, args.get(0));
        o.setValue(InternedString::i, args.get(1));
    } else {
        uasserted(ErrorCodes::BadValue, "Timestamp needs 0 or 2 arguments");
    }

    args.rval().setObjectOrNull(thisv);
}
Esempio n. 8
0
void DBCollectionInfo::construct(JSContext* cx, JS::CallArgs args) {
    auto scope = getScope(cx);

    if (args.length() != 4)
        uasserted(ErrorCodes::BadValue, "collection constructor requires 4 arguments");

    for (unsigned i = 0; i < args.length(); ++i) {
        uassert(ErrorCodes::BadValue,
                "collection constructor called with undefined argument",
                !args.get(i).isUndefined());
    }

    JS::RootedObject thisv(cx);
    scope->getDbCollectionProto().newObject(&thisv);
    ObjectWrapper o(cx, thisv);

    o.setValue("_mongo", args.get(0));
    o.setValue("_db", args.get(1));
    o.setValue("_shortName", args.get(2));
    o.setValue("_fullName", args.get(3));

    std::string fullName = ValueWriter(cx, args.get(3)).toString();

    auto context = scope->getOpContext();
    if (context && haveLocalShardingInfo(context->getClient(), fullName))
        uasserted(ErrorCodes::BadValue, "can't use sharded collection from db.eval");

    args.rval().setObjectOrNull(thisv);
}
Esempio n. 9
0
void SessionInfo::Functions::setTxnState::call(JSContext* cx, JS::CallArgs args) {
    auto holder = getHolder(args);
    invariant(holder);
    uassert(ErrorCodes::BadValue, "setTxnState takes 1 argument", args.length() == 1);

    auto arg = args.get(0);
    holder->txnState = transactionStateEnum(ValueWriter(cx, arg).toString().c_str());
    args.rval().setUndefined();
}
Esempio n. 10
0
void SessionInfo::Functions::setTxnNumber::call(JSContext* cx, JS::CallArgs args) {
    auto holder = getHolder(args);
    invariant(holder);
    uassert(ErrorCodes::BadValue, "setTxnNumber takes 1 argument", args.length() == 1);

    auto arg = args.get(0);
    holder->txnNumber = ValueWriter(cx, arg).toInt64();
    args.rval().setUndefined();
}
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();
}
Esempio n. 12
0
void BinDataInfo::Functions::MD5::call(JSContext* cx, JS::CallArgs args) {
    if (args.length() != 1)
        uasserted(ErrorCodes::BadValue, "MD5 needs 1 argument");

    auto arg = args.get(0);
    auto str = ValueWriter(cx, arg).toString();

    if (str.length() != 32)
        uasserted(ErrorCodes::BadValue, "MD5 string must have 32 characters");

    hexToBinData(cx, MD5Type, arg, args.rval());
}
Esempio n. 13
0
File: oid.cpp Progetto: DINKIN/mongo
void OIDInfo::construct(JSContext* cx, JS::CallArgs args) {
    OID oid;
    if (args.length() == 0) {
        oid.init();
    } else {
        auto str = ValueWriter(cx, args.get(0)).toString();

        Scope::validateObjectIdString(str);
        oid.init(str);
    }

    make(cx, oid, args.rval());
}
Esempio n. 14
0
bool MozJSImplScope::_checkErrorState(bool success, bool reportError, bool assertOnError) {
    if (success)
        return false;

    if (_quickExit)
        return false;

    if (_status.isOK()) {
        JS::RootedValue excn(_context);
        if (JS_GetPendingException(_context, &excn) && excn.isObject()) {
            str::stream ss;

            JS::RootedValue stack(_context);

            ObjectWrapper(_context, excn).getValue("stack", &stack);

            ss << ValueWriter(_context, excn).toString() << " :\n"
               << ValueWriter(_context, stack).toString();
            _status = Status(ErrorCodes::JSInterpreterFailure, ss);
        } else {
            _status = Status(ErrorCodes::UnknownError, "Unknown Failure from JSInterpreter");
        }
    }

    _error = _status.reason();

    if (reportError)
        error() << _error << std::endl;

    // Clear the status state
    auto status = std::move(_status);

    if (assertOnError) {
        // Throw if necessary
        uassertStatusOK(status);
    }

    return true;
}
Esempio n. 15
0
void BinDataInfo::construct(JSContext* cx, JS::CallArgs args) {
    auto scope = getScope(cx);

    if (args.length() != 2) {
        uasserted(ErrorCodes::BadValue, "BinData takes 2 arguments -- BinData(subtype,data)");
    }

    auto type = args.get(0);
    auto typeNumber = ValueWriter(cx, type).toInt32();
    if (!type.isNumber() || typeNumber < 0 || typeNumber > 255) {
        uasserted(ErrorCodes::BadValue,
                  "BinData subtype must be a Number between 0 and 255 inclusive");
    }

    auto utf = args.get(1);

    if (!utf.isString()) {
        uasserted(ErrorCodes::BadValue, "BinData data must be a String");
    }

    auto str = ValueWriter(cx, utf).toString();

    auto tmpBase64 = base64::decode(str);

    JS::RootedObject thisv(cx);
    scope->getProto<BinDataInfo>().newObject(&thisv);
    ObjectWrapper o(cx, thisv);

    JS::RootedValue len(cx);
    len.setInt32(tmpBase64.length());

    o.defineProperty(InternedString::len, len, JSPROP_READONLY);
    o.defineProperty(InternedString::type, type, JSPROP_READONLY);

    JS_SetPrivate(thisv, scope->trackedNew<std::string>(std::move(str)));

    args.rval().setObjectOrNull(thisv);
}
Esempio n. 16
0
void ObjectInfo::Functions::bsonsize::call(JSContext* cx, JS::CallArgs args) {
    if (args.length() != 1)
        uasserted(ErrorCodes::BadValue, "bsonsize needs 1 argument");

    if (args.get(0).isNull()) {
        args.rval().setInt32(0);
        return;
    }

    if (!args.get(0).isObject())
        uasserted(ErrorCodes::BadValue, "argument to bsonsize has to be an object");

    args.rval().setInt32(ValueWriter(cx, args.get(0)).toBSON().objsize());
}
Esempio n. 17
0
void NumberDecimalInfo::construct(JSContext* cx, JS::CallArgs args) {
    auto scope = getScope(cx);

    JS::RootedObject thisv(cx);

    scope->getProto<NumberDecimalInfo>().newObject(&thisv);

    Decimal128 x(0);

    if (args.length() == 0) {
        // Do nothing
    } else if (args.length() == 1) {
        x = ValueWriter(cx, args.get(0)).toDecimal128();
    } else {
        uasserted(ErrorCodes::BadValue, "NumberDecimal takes 0 or 1 arguments");
    }

    JS_SetPrivate(thisv, scope->trackedNew<Decimal128>(x));

    args.rval().setObjectOrNull(thisv);
}
Esempio n. 18
0
void NumberIntInfo::construct(JSContext* cx, JS::CallArgs args) {
    auto scope = getScope(cx);

    JS::RootedObject thisv(cx);

    scope->getProto<NumberIntInfo>().newObject(&thisv);

    int32_t x = 0;

    if (args.length() == 0) {
        // Do nothing
    } else if (args.length() == 1) {
        x = ValueWriter(cx, args.get(0)).toInt32();
    } else {
        uasserted(ErrorCodes::BadValue, "NumberInt takes 0 or 1 arguments");
    }

    JS_SetPrivate(thisv, new int(x));

    args.rval().setObjectOrNull(thisv);
}
Esempio n. 19
0
bool MozJSImplScope::exec(StringData code,
                          const std::string& name,
                          bool printResult,
                          bool reportError,
                          bool assertOnError,
                          int timeoutMs) {
    MozJSEntry entry(this);

    JS::CompileOptions co(_context);
    setCompileOptions(&co);
    co.setFile(name.c_str());
    JS::RootedScript script(_context);

    bool success = JS::Compile(_context, _global, co, code.rawData(), code.size(), &script);

    if (_checkErrorState(success, reportError, assertOnError))
        return false;

    if (timeoutMs)
        _engine->getDeadlineMonitor().startDeadline(this, timeoutMs);

    JS::RootedValue out(_context);

    success = JS_ExecuteScript(_context, _global, script, &out);

    if (timeoutMs)
        _engine->getDeadlineMonitor().stopDeadline(this);

    if (_checkErrorState(success, reportError, assertOnError))
        return false;

    ObjectWrapper(_context, _global).setValue(kExecResult, out);

    if (printResult && !out.isUndefined()) {
        // appears to only be used by shell
        std::cout << ValueWriter(_context, out).toString() << std::endl;
    }

    return true;
}
Esempio n. 20
0
void MozJSImplScope::_reportError(JSContext* cx, const char* message, JSErrorReport* report) {
    auto scope = getScope(cx);

    if (!JSREPORT_IS_WARNING(report->flags)) {
        str::stream ss;
        ss << message;

        // TODO: something far more elaborate that mimics the stack printing from v8
        JS::RootedValue excn(cx);
        if (JS_GetPendingException(cx, &excn) && excn.isObject()) {
            JS::RootedValue stack(cx);

            ObjectWrapper(cx, excn).getValue("stack", &stack);

            ss << " :\n" << ValueWriter(cx, stack).toString();
        }

        scope->_status =
            Status(report->errorNumber ? static_cast<ErrorCodes::Error>(report->errorNumber)
                                       : ErrorCodes::JSInterpreterFailure,
                   ss);
    }
}
Esempio n. 21
0
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);
}
Esempio n. 22
0
double ObjectWrapper::getNumber(Key key) {
    JS::RootedValue x(_context);
    getValue(key, &x);

    return ValueWriter(_context, x).toNumber();
}
Esempio n. 23
0
long long ObjectWrapper::getNumberLongLong(Key key) {
    JS::RootedValue x(_context);
    getValue(key, &x);

    return ValueWriter(_context, x).toInt64();
}
Esempio n. 24
0
int ObjectWrapper::type(Key key) {
    JS::RootedValue x(_context);
    getValue(key, &x);

    return ValueWriter(_context, x).type();
}
Esempio n. 25
0
Decimal128 ObjectWrapper::getNumberDecimal(Key key) {
    JS::RootedValue x(_context);
    getValue(key, &x);

    return ValueWriter(_context, x).toDecimal128();
}
Esempio n. 26
0
void ValueWriter::_writeObject(BSONObjBuilder* b,
                               StringData sd,
                               ObjectWrapper::WriteFieldRecursionFrames* frames) {
    auto scope = getScope(_context);

    // We open a block here because it's important that the two rooting types
    // we need (obj and o) go out of scope before we actually open a
    // new WriteFieldFrame (in the emplace at the bottom of the function). If
    // we don't do this, we'll destroy the local roots in this function body
    // before the frame we added, which will break the gc rooting list.
    {
        JS::RootedObject obj(_context, _value.toObjectOrNull());
        ObjectWrapper o(_context, obj);

        auto jsclass = JS_GetClass(obj);

        if (jsclass) {
            if (scope->getProto<OIDInfo>().getJSClass() == jsclass) {
                b->append(sd, OIDInfo::getOID(_context, obj));

                return;
            }

            if (scope->getProto<NumberLongInfo>().getJSClass() == jsclass) {
                long long out = NumberLongInfo::ToNumberLong(_context, obj);
                b->append(sd, out);

                return;
            }

            if (scope->getProto<NumberIntInfo>().getJSClass() == jsclass) {
                b->append(sd, NumberIntInfo::ToNumberInt(_context, obj));

                return;
            }

            if (scope->getProto<CodeInfo>().getJSClass() == jsclass) {
                if (o.hasOwnField(InternedString::scope)  // CodeWScope
                    &&
                    o.type(InternedString::scope) == mongo::Object) {
                    if (o.type(InternedString::code) != mongo::String) {
                        uasserted(ErrorCodes::BadValue, "code must be a string");
                    }

                    b->appendCodeWScope(
                        sd, o.getString(InternedString::code), o.getObject(InternedString::scope));
                } else {  // Code
                    if (o.type(InternedString::code) != mongo::String) {
                        uasserted(ErrorCodes::BadValue, "code must be a string");
                    }

                    b->appendCode(sd, o.getString(InternedString::code));
                }
                return;
            }

            if (scope->getProto<NumberDecimalInfo>().getJSClass() == jsclass) {
                b->append(sd, NumberDecimalInfo::ToNumberDecimal(_context, obj));

                return;
            }

            if (scope->getProto<DBPointerInfo>().getJSClass() == jsclass) {
                JS::RootedValue id(_context);
                o.getValue("id", &id);

                b->appendDBRef(sd, o.getString("ns"), OIDInfo::getOID(_context, id));

                return;
            }

            if (scope->getProto<BinDataInfo>().getJSClass() == jsclass) {
                auto str = static_cast<std::string*>(JS_GetPrivate(obj));

                auto binData = base64::decode(*str);

                b->appendBinData(sd,
                                 binData.size(),
                                 static_cast<mongo::BinDataType>(
                                     static_cast<int>(o.getNumber(InternedString::type))),
                                 binData.c_str());

                return;
            }

            if (scope->getProto<TimestampInfo>().getJSClass() == jsclass) {
                Timestamp ot(o.getNumber("t"), o.getNumber("i"));
                b->append(sd, ot);

                return;
            }

            if (scope->getProto<MinKeyInfo>().getJSClass() == jsclass) {
                b->appendMinKey(sd);

                return;
            }

            if (scope->getProto<MaxKeyInfo>().getJSClass() == jsclass) {
                b->appendMaxKey(sd);

                return;
            }
        }

        auto protoKey = JS::IdentifyStandardInstance(obj);

        switch (protoKey) {
            case JSProto_Function: {
                uassert(16716,
                        "cannot convert native function to BSON",
                        !scope->getProto<NativeFunctionInfo>().instanceOf(obj));
                JSStringWrapper jsstr;
                b->appendCode(sd, ValueWriter(_context, _value).toStringData(&jsstr));
                return;
            }
            case JSProto_RegExp: {
                JS::RootedValue v(_context);
                v.setObjectOrNull(obj);

                std::string regex = ValueWriter(_context, v).toString();
                regex = regex.substr(1);
                std::string r = regex.substr(0, regex.rfind('/'));
                std::string o = regex.substr(regex.rfind('/') + 1);

                b->appendRegex(sd, r, o);

                return;
            }
            case JSProto_Date: {
                JS::RootedValue dateval(_context);
                o.callMethod("getTime", &dateval);

                auto d = Date_t::fromMillisSinceEpoch(ValueWriter(_context, dateval).toInt64());
                b->appendDate(sd, d);

                return;
            }
            default:
                break;
        }
    }

    // nested object or array

    // This emplace is effectively a recursive function call, as this code path
    // unwinds back to ObjectWrapper::toBSON. In that function we'll actually
    // write the child we've just pushed onto the frames stack.
    frames->emplace(_context, _value.toObjectOrNull(), b, sd);
}
Esempio n. 27
0
BSONObj ObjectWrapper::getObject(Key key) {
    JS::RootedValue x(_context);
    getValue(key, &x);

    return ValueWriter(_context, x).toBSON();
}
Esempio n. 28
0
int ObjectWrapper::getNumberInt(Key key) {
    JS::RootedValue x(_context);
    getValue(key, &x);

    return ValueWriter(_context, x).toInt32();
}
Esempio n. 29
0
std::string ObjectWrapper::getString(Key key) {
    JS::RootedValue x(_context);
    getValue(key, &x);

    return ValueWriter(_context, x).toString();
}
Esempio n. 30
0
bool ObjectWrapper::getBoolean(Key key) {
    JS::RootedValue x(_context);
    getValue(key, &x);

    return ValueWriter(_context, x).toBoolean();
}