couchdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From fdman...@apache.org
Subject svn commit: r1080953 - in /couchdb/trunk: share/www/script/test/replicator_db.js src/couchdb/couch_js_functions.hrl
Date Sat, 12 Mar 2011 17:33:52 GMT
Author: fdmanana
Date: Sat Mar 12 17:33:51 2011
New Revision: 1080953

URL: http://svn.apache.org/viewvc?rev=1080953&view=rev
Log:
Replicator manager: do basic validation of replication documents

Now the default design document of the replicator database validates
each replication document added to the database so that necessary
fields must be present and have the right type, and optional replication
related fields have the correct type as well.

Closes COUCHDB-1088.


Modified:
    couchdb/trunk/share/www/script/test/replicator_db.js
    couchdb/trunk/src/couchdb/couch_js_functions.hrl

Modified: couchdb/trunk/share/www/script/test/replicator_db.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/replicator_db.js?rev=1080953&r1=1080952&r2=1080953&view=diff
==============================================================================
--- couchdb/trunk/share/www/script/test/replicator_db.js (original)
+++ couchdb/trunk/share/www/script/test/replicator_db.js Sat Mar 12 17:33:51 2011
@@ -916,6 +916,131 @@ couchTests.replicator_db = function(debu
   }
 
 
+  function rep_doc_field_validation() {
+    var docs = makeDocs(1, 5);
+
+    populate_db(dbA, docs);
+    populate_db(dbB, []);
+
+    var repDoc = {
+       _id: "rep1",
+       target: dbB.name
+    };
+
+    try {
+      repDb.save(repDoc);
+      T(false, "should have failed because source field is missing");
+    } catch (x) {
+      TEquals("forbidden", x.error);
+    }
+
+    repDoc = {
+       _id: "rep1",
+       source: 123,
+       target: dbB.name
+    };
+
+    try {
+      repDb.save(repDoc);
+      T(false, "should have failed because source field is a number");
+    } catch (x) {
+      TEquals("forbidden", x.error);
+    }
+
+    repDoc = {
+       _id: "rep1",
+       source: dbA.name
+    };
+
+    try {
+      repDb.save(repDoc);
+      T(false, "should have failed because target field is missing");
+    } catch (x) {
+      TEquals("forbidden", x.error);
+    }
+
+    repDoc = {
+       _id: "rep1",
+       source: dbA.name,
+       target: null
+    };
+
+    try {
+      repDb.save(repDoc);
+      T(false, "should have failed because target field is null");
+    } catch (x) {
+      TEquals("forbidden", x.error);
+    }
+
+    repDoc = {
+       _id: "rep1",
+       source: dbA.name,
+       target: { url: 123 }
+    };
+
+    try {
+      repDb.save(repDoc);
+      T(false, "should have failed because target.url field is not a string");
+    } catch (x) {
+      TEquals("forbidden", x.error);
+    }
+
+    repDoc = {
+       _id: "rep1",
+       source: dbA.name,
+       target: { url: dbB.name, auth: null }
+    };
+
+    try {
+      repDb.save(repDoc);
+      T(false, "should have failed because target.auth field is null");
+    } catch (x) {
+      TEquals("forbidden", x.error);
+    }
+
+    repDoc = {
+       _id: "rep1",
+       source: dbA.name,
+       target: { url: dbB.name, auth: "foo:bar" }
+    };
+
+    try {
+      repDb.save(repDoc);
+      T(false, "should have failed because target.auth field is not an object");
+    } catch (x) {
+      TEquals("forbidden", x.error);
+    }
+
+    repDoc = {
+       _id: "rep1",
+       source: dbA.name,
+       target: dbB.name,
+       continuous: "true"
+    };
+
+    try {
+      repDb.save(repDoc);
+      T(false, "should have failed because continuous is not a boolean");
+    } catch (x) {
+      TEquals("forbidden", x.error);
+    }
+
+    repDoc = {
+       _id: "rep1",
+       source: dbA.name,
+       target: dbB.name,
+       filter: 123
+    };
+
+    try {
+      repDb.save(repDoc);
+      T(false, "should have failed because filter is not a string");
+    } catch (x) {
+      TEquals("forbidden", x.error);
+    }
+  }
+
+
   // run all the tests
   var server_config = [
     {
@@ -983,6 +1108,10 @@ couchTests.replicator_db = function(debu
   restartServer();
   run_on_modified_server(server_config, compact_rep_db);
 
+  repDb.deleteDb();
+  restartServer();
+  run_on_modified_server(server_config, rep_doc_field_validation);
+
 /*
  * Disabled, since error state would be set on the document only after
  * the exponential backoff retry done by the replicator database listener

Modified: couchdb/trunk/src/couchdb/couch_js_functions.hrl
URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_js_functions.hrl?rev=1080953&r1=1080952&r2=1080953&view=diff
==============================================================================
--- couchdb/trunk/src/couchdb/couch_js_functions.hrl (original)
+++ couchdb/trunk/src/couchdb/couch_js_functions.hrl Sat Mar 12 17:33:51 2011
@@ -110,32 +110,100 @@
     function(newDoc, oldDoc, userCtx) {
         function reportError(error_msg) {
             log('Error writing document `' + newDoc._id +
-                '` to replicator DB: ' + error_msg);
+                '\\' to the replicator database: ' + error_msg);
             throw({forbidden: error_msg});
         }
 
+        function validateEndpoint(endpoint, fieldName) {
+            if ((typeof endpoint !== 'string') &&
+                ((typeof endpoint !== 'object') || (endpoint === null))) {
+
+                reportError('The `' + fieldName + '\\' property must exist' +
+                    ' and be either a string or an object.');
+            }
+
+            if (typeof endpoint === 'object') {
+                if ((typeof endpoint.url !== 'string') || !endpoint.url) {
+                    reportError('The url property must exist in the `' +
+                        fieldName + '\\' field and must be a non-empty string.');
+                }
+
+                if ((typeof endpoint.auth !== 'undefined') &&
+                    ((typeof endpoint.auth !== 'object') ||
+                        endpoint.auth === null)) {
+
+                    reportError('`' + fieldName +
+                        '.auth\\' must be a non-null object.');
+                }
+
+                if ((typeof endpoint.headers !== 'undefined') &&
+                    ((typeof endpoint.headers !== 'object') ||
+                        endpoint.headers === null)) {
+
+                    reportError('`' + fieldName +
+                        '.headers\\' must be a non-null object.');
+                }
+            }
+        }
+
         var isReplicator = (userCtx.roles.indexOf('_replicator') >= 0);
         if (oldDoc && !newDoc._deleted && !isReplicator) {
             reportError('Only the replicator can edit replication documents.');
         }
 
+        if (!newDoc._deleted) {
+            validateEndpoint(newDoc.source, 'source');
+            validateEndpoint(newDoc.target, 'target');
+
+            if ((typeof newDoc.create_target !== 'undefined') &&
+                (typeof newDoc.create_target !== 'boolean')) {
+
+                reportError('The `create_target\\' field must be a boolean.');
+            }
+
+            if ((typeof newDoc.continuous !== 'undefined') &&
+                (typeof newDoc.continuous !== 'boolean')) {
+
+                reportError('The `continuous\\' field must be a boolean.');
+            }
+
+            if ((typeof newDoc.doc_ids !== 'undefined') &&
+                !isArray(newDoc.doc_ids)) {
+
+                reportError('The `doc_ids\\' field must be an array of strings.');
+            }
+
+            if ((typeof newDoc.filter !== 'undefined') &&
+                ((typeof newDoc.filter !== 'string') || !newDoc.filter)) {
+
+                reportError('The `filter\\' field must be a non-empty string.');
+            }
+
+            if ((typeof newDoc.query_params !== 'undefined') &&
+                ((typeof newDoc.query_params !== 'object') ||
+                    newDoc.query_params === null)) {
+
+                reportError('The `query_params\\' field must be an object.');
+            }
+        }
+
         if (newDoc.user_ctx) {
             var user_ctx = newDoc.user_ctx;
 
             if (typeof user_ctx !== 'object') {
-                reportError('The user_ctx property must be an object.');
+                reportError('The `user_ctx\\' property must be an object.');
             }
 
             if (!(user_ctx.name === null ||
                     (typeof user_ctx.name === 'undefined') ||
                     ((typeof user_ctx.name === 'string') &&
                         user_ctx.name.length > 0))) {
-                reportError('The name property of the user_ctx must be a ' +
+                reportError('The `user_ctx.name\\' property must be a ' +
                     'non-empty string.');
             }
 
             if (user_ctx.roles && !isArray(user_ctx.roles)) {
-                reportError('The roles property of the user_ctx must be ' +
+                reportError('The `user_ctx.roles\\' property must be ' +
                     'an array of strings.');
             }
 



Mime
View raw message