summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--db/namespace.cpp14
-rw-r--r--db/namespace.h7
-rw-r--r--db/pdfile.cpp2
-rw-r--r--db/query.cpp6
-rw-r--r--jstests/storefunc.js31
-rw-r--r--scripting/engine.cpp43
-rw-r--r--scripting/engine.h14
-rw-r--r--scripting/engine_spidermonkey.cpp12
8 files changed, 119 insertions, 10 deletions
diff --git a/db/namespace.cpp b/db/namespace.cpp
index b37eb8c6727..c3fe9485402 100644
--- a/db/namespace.cpp
+++ b/db/namespace.cpp
@@ -21,6 +21,7 @@
#include "db.h"
#include "../util/mmap.h"
#include "../util/hashtab.h"
+#include "../scripting/engine.h"
#include "btree.h"
#include <algorithm>
#include <list>
@@ -692,5 +693,18 @@ namespace mongo {
deleteObjects( s.c_str(), oldIndexSpec.getOwned(), true, false, true );
}
}
+
+ bool legalClientSystemNS( const string& ns , bool write ){
+ if ( ns.find( ".system.users" ) != string::npos )
+ return true;
+
+ if ( ns.find( ".system.js" ) != string::npos ){
+ if ( write )
+ Scope::storedFuncMod();
+ return true;
+ }
+
+ return false;
+ }
} // namespace mongo
diff --git a/db/namespace.h b/db/namespace.h
index 58e66bac17d..dca7e685a05 100644
--- a/db/namespace.h
+++ b/db/namespace.h
@@ -126,6 +126,13 @@ namespace mongo {
char buf[MaxNsLen];
};
+ /**
+ @return true if a client can modify this namespace
+ things like *.system.users
+ */
+ bool legalClientSystemNS( const string& ns , bool write );
+
+
/* deleted lists -- linked lists of deleted records -- are placed in 'buckets' of various sizes
so you can look for a deleterecord about the right size.
*/
diff --git a/db/pdfile.cpp b/db/pdfile.cpp
index 599bc5736dc..04bec88ba0e 100644
--- a/db/pdfile.cpp
+++ b/db/pdfile.cpp
@@ -1302,7 +1302,7 @@ assert( !eloc.isNull() );
// later:check for dba-type permissions here if have that at some point separate
if ( strstr(ns, ".system.indexes" ) )
wouldAddIndex = true;
- else if ( strstr(ns, ".system.users") )
+ else if ( legalClientSystemNS( ns , true ) )
;
else if ( !god ) {
out() << "ERROR: attempt to insert in system namespace " << ns << endl;
diff --git a/db/query.cpp b/db/query.cpp
index c6d40b6fd67..d2890422365 100644
--- a/db/query.cpp
+++ b/db/query.cpp
@@ -112,9 +112,7 @@ namespace mongo {
if done here, as there are pointers into those objects in
NamespaceDetails.
*/
- if( strstr(ns, ".system.users") )
- ;
- else {
+ if( ! legalClientSystemNS( ns , true ) ){
uasserted("cannot delete from system namespace");
return -1;
}
@@ -752,7 +750,7 @@ namespace mongo {
uassert("cannot update reserved $ collection", strchr(ns, '$') == 0 );
if ( strstr(ns, ".system.") ) {
- uassert("cannot update system collection", strstr(ns, ".system.users"));
+ uassert("cannot update system collection", legalClientSystemNS( ns , true ) );
}
QueryPlanSet qps( ns, pattern, BSONObj() );
diff --git a/jstests/storefunc.js b/jstests/storefunc.js
new file mode 100644
index 00000000000..bae109035fe
--- /dev/null
+++ b/jstests/storefunc.js
@@ -0,0 +1,31 @@
+
+s = db.system.js;
+s.remove({});
+assert.eq( 0 , s.count() , "setup - A" );
+
+s.save( { _id : "x" , value : "3" } );
+assert.isnull( db.getLastError() , "setup - B" );
+assert.eq( 1 , s.count() , "setup - C" );
+
+s.remove( { _id : "x" } );
+assert.eq( 0 , s.count() , "setup - D" );
+s.save( { _id : "x" , value : "4" } );
+assert.eq( 1 , s.count() , "setup - E" );
+
+assert.eq( 4 , s.findOne().value , "setup - F" );
+s.update( { _id : "x" } , { $set : { value : 5 } } );
+assert.eq( 1 , s.count() , "setup - G" );
+assert.eq( 5 , s.findOne().value , "setup - H" );
+
+assert.eq( 5 , db.eval( "return x" ) , "exec - 1 " );
+
+s.update( { _id : "x" } , { $set : { value : 6 } } );
+assert.eq( 1 , s.count() , "setup2 - A" );
+assert.eq( 6 , s.findOne().value , "setup - B" );
+
+assert.eq( 6 , db.eval( "return x" ) , "exec - 2 " );
+
+
+
+s.insert( { _id : "bar" , value : function( z ){ return 17 + z; } } );
+assert.eq( 22 , db.eval( "return bar(5);" ) , "exec - 3 " );
diff --git a/scripting/engine.cpp b/scripting/engine.cpp
index 5c53cdd1f65..c82f5961563 100644
--- a/scripting/engine.cpp
+++ b/scripting/engine.cpp
@@ -3,10 +3,13 @@
#include "stdafx.h"
#include "engine.h"
#include "../util/file.h"
+#include "../client/dbclient.h"
namespace mongo {
+
+ long long Scope::_lastVersion = 1;
- Scope::Scope(){
+ Scope::Scope() : _localDBName("") , _loadedVersion(0){
}
Scope::~Scope(){
@@ -88,6 +91,37 @@ namespace mongo {
return exec( data , filename , printResult , reportError , assertOnError, timeoutMs );
}
+
+ void Scope::storedFuncMod(){
+ _lastVersion++;
+ }
+
+ void Scope::loadStored( bool ignoreNotConnected ){
+ if ( _localDBName.size() == 0 ){
+ if ( ignoreNotConnected )
+ return;
+ uassert( "need to have locallyConnected already" , _localDBName.size() );
+ }
+ if ( _loadedVersion == _lastVersion )
+ return;
+
+ _loadedVersion = _lastVersion;
+
+ static DBClientBase * db = createDirectClient();
+
+ auto_ptr<DBClientCursor> c = db->query( _localDBName + ".system.js" , Query() );
+ while ( c->more() ){
+ BSONObj o = c->next();
+
+ BSONElement n = o["_id"];
+ BSONElement v = o["value"];
+
+ uassert( "name has to be a string" , n.type() == String );
+ uassert( "value has to be set" , v.type() != EOO );
+
+ setElement( n.valuestr() , v );
+ }
+ }
typedef map< string , list<Scope*> > PoolToScopes;
@@ -157,7 +191,9 @@ namespace mongo {
class PooledScope : public Scope {
public:
- PooledScope( const string pool , Scope * real ) : _pool( pool ) , _real( real ){};
+ PooledScope( const string pool , Scope * real ) : _pool( pool ) , _real( real ){
+ _real->loadStored( true );
+ };
virtual ~PooledScope(){
ScopeCache * sc = scopeCache.get();
if ( sc ){
@@ -202,6 +238,9 @@ namespace mongo {
return _real->type( field );
}
+ void setElement( const char *field , const BSONElement& val ){
+ _real->setElement( field , val );
+ }
void setNumber( const char *field , double val ){
_real->setNumber( field , val );
}
diff --git a/scripting/engine.h b/scripting/engine.h
index 50b0dee6dea..fb9aa48dbc2 100644
--- a/scripting/engine.h
+++ b/scripting/engine.h
@@ -36,6 +36,7 @@ namespace mongo {
void append( BSONObjBuilder & builder , const char * fieldName , const char * scopeName );
+ virtual void setElement( const char *field , const BSONElement& e ) = 0;
virtual void setNumber( const char *field , double val ) = 0;
virtual void setString( const char *field , const char * val ) = 0;
virtual void setObject( const char *field , const BSONObj& obj , bool readOnly=true ) = 0;
@@ -67,6 +68,19 @@ namespace mongo {
virtual void injectNative( const char *field, NativeFunction func ) = 0;
virtual void gc() = 0;
+
+ void loadStored( bool ignoreNotConnected = false );
+
+ /**
+ if any changes are made to .system.js, call this
+ right now its just global - slightly inefficient, but a lot simpler
+ */
+ static void storedFuncMod();
+
+ protected:
+ string _localDBName;
+ long long _loadedVersion;
+ static long long _lastVersion;
};
class ScriptEngine : boost::noncopyable {
diff --git a/scripting/engine_spidermonkey.cpp b/scripting/engine_spidermonkey.cpp
index 0fbeb0bb3db..88a410544a1 100644
--- a/scripting/engine_spidermonkey.cpp
+++ b/scripting/engine_spidermonkey.cpp
@@ -1008,7 +1008,7 @@ namespace mongo {
smlock;
uassert( "already setup for external db" , ! _externalSetup );
if ( _localConnect ){
- uassert( "connected to different db" , _dbName == dbName );
+ uassert( "connected to different db" , _localDBName == dbName );
return;
}
@@ -1018,7 +1018,8 @@ namespace mongo {
exec( ((string)"db = _mongo.getDB( \"" + dbName + "\" ); ").c_str() );
_localConnect = true;
- _dbName = dbName;
+ _localDBName = dbName;
+ loadStored();
}
// ----- getters ------
@@ -1082,6 +1083,12 @@ namespace mongo {
// ----- setters ------
+ void setElement( const char *field , const BSONElement& val ){
+ smlock;
+ jsval v = _convertor->toval( val );
+ assert( JS_SetProperty( _context , _global , field , &v ) );
+ }
+
void setNumber( const char *field , double val ){
smlock;
jsval v = _convertor->toval( val );
@@ -1301,7 +1308,6 @@ namespace mongo {
bool _externalSetup;
bool _localConnect;
- string _dbName;
set<string> _initFieldNames;