You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by da...@apache.org on 2009/03/13 22:12:45 UTC

svn commit: r753413 [1/2] - in /couchdb/branches/rep_security: ./ bin/ etc/couchdb/ etc/default/ share/server/ share/www/ share/www/script/ share/www/script/test/ share/www/style/ src/couchdb/ src/ibrowse/

Author: damien
Date: Fri Mar 13 21:12:44 2009
New Revision: 753413

URL: http://svn.apache.org/viewvc?rev=753413&view=rev
Log:
Merge from trunk. Test failures in list_views need to be fixed.

Added:
    couchdb/branches/rep_security/share/www/script/test/attachment_names.js
      - copied, changed from r753015, couchdb/trunk/share/www/script/test/attachment_names.js
    couchdb/branches/rep_security/src/couchdb/couch_rep_sup.erl
      - copied unchanged from r753015, couchdb/trunk/src/couchdb/couch_rep_sup.erl
Modified:
    couchdb/branches/rep_security/   (props changed)
    couchdb/branches/rep_security/CHANGES
    couchdb/branches/rep_security/bin/couchdb.tpl.in
    couchdb/branches/rep_security/etc/couchdb/default.ini.tpl.in
    couchdb/branches/rep_security/etc/default/couchdb   (props changed)
    couchdb/branches/rep_security/share/server/main.js
    couchdb/branches/rep_security/share/www/database.html
    couchdb/branches/rep_security/share/www/index.html
    couchdb/branches/rep_security/share/www/script/couch.js
    couchdb/branches/rep_security/share/www/script/couch_tests.js
    couchdb/branches/rep_security/share/www/script/futon.browse.js
    couchdb/branches/rep_security/share/www/script/jquery.couch.js
    couchdb/branches/rep_security/share/www/script/test/   (props changed)
    couchdb/branches/rep_security/share/www/script/test/etags_views.js
    couchdb/branches/rep_security/share/www/script/test/list_views.js
    couchdb/branches/rep_security/share/www/script/test/replication.js
    couchdb/branches/rep_security/share/www/script/test/show_documents.js
    couchdb/branches/rep_security/share/www/style/layout.css
    couchdb/branches/rep_security/src/couchdb/Makefile.am
    couchdb/branches/rep_security/src/couchdb/couch_db.hrl
    couchdb/branches/rep_security/src/couchdb/couch_doc.erl
    couchdb/branches/rep_security/src/couchdb/couch_external_server.erl
    couchdb/branches/rep_security/src/couchdb/couch_httpd.erl
    couchdb/branches/rep_security/src/couchdb/couch_httpd_db.erl
    couchdb/branches/rep_security/src/couchdb/couch_httpd_external.erl
    couchdb/branches/rep_security/src/couchdb/couch_httpd_misc_handlers.erl
    couchdb/branches/rep_security/src/couchdb/couch_httpd_show.erl
    couchdb/branches/rep_security/src/couchdb/couch_httpd_view.erl
    couchdb/branches/rep_security/src/couchdb/couch_os_process.erl
    couchdb/branches/rep_security/src/couchdb/couch_rep.erl
    couchdb/branches/rep_security/src/couchdb/couch_server_sup.erl
    couchdb/branches/rep_security/src/couchdb/couch_util.erl
    couchdb/branches/rep_security/src/ibrowse/ibrowse.erl
    couchdb/branches/rep_security/src/ibrowse/ibrowse_http_client.erl
    couchdb/branches/rep_security/src/ibrowse/ibrowse_test.erl

Propchange: couchdb/branches/rep_security/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Fri Mar 13 21:12:44 2009
@@ -1,2 +1,3 @@
+/couchdb/branches/design_resources:751716-751803
 /couchdb/branches/form:729440-730015
-/couchdb/trunk:741843-750305
+/couchdb/trunk:741843-753015

Modified: couchdb/branches/rep_security/CHANGES
URL: http://svn.apache.org/viewvc/couchdb/branches/rep_security/CHANGES?rev=753413&r1=753412&r2=753413&view=diff
==============================================================================
--- couchdb/branches/rep_security/CHANGES (original)
+++ couchdb/branches/rep_security/CHANGES Fri Mar 13 21:12:44 2009
@@ -17,6 +17,13 @@
  * Added pagination to the database listing page.
  * Implemented attachment uploading from the document page.
 
+Design Document Resource Paths:
+
+ * Added httpd_design_handlers config section.
+ * Moved _view to httpd_design_handlers.
+ * Added ability to render documents as non-JSON content-types with _show and 
+   _list functions, which are also httpd_design_handlers.
+
 Version 0.8.1-incubating
 ------------------------
 

Modified: couchdb/branches/rep_security/bin/couchdb.tpl.in
URL: http://svn.apache.org/viewvc/couchdb/branches/rep_security/bin/couchdb.tpl.in?rev=753413&r1=753412&r2=753413&view=diff
==============================================================================
--- couchdb/branches/rep_security/bin/couchdb.tpl.in (original)
+++ couchdb/branches/rep_security/bin/couchdb.tpl.in Fri Mar 13 21:12:44 2009
@@ -207,7 +207,7 @@
                 export HEART_COMMAND
                 export HEART_BEAT_TIMEOUT
                 `eval $command -pidfile $PID_FILE -heart \
-                    > $STDOUT_FILE 2> $STDERR_FILE` || true
+                    >> $STDOUT_FILE 2>> $STDERR_FILE` || true
                 PID=`_get_pid`
                 if test -n "$PID"; then
                     if kill -0 $PID 2> /dev/null; then

Modified: couchdb/branches/rep_security/etc/couchdb/default.ini.tpl.in
URL: http://svn.apache.org/viewvc/couchdb/branches/rep_security/etc/couchdb/default.ini.tpl.in?rev=753413&r1=753412&r2=753413&view=diff
==============================================================================
--- couchdb/branches/rep_security/etc/couchdb/default.ini.tpl.in (original)
+++ couchdb/branches/rep_security/etc/couchdb/default.ini.tpl.in Fri Mar 13 21:12:44 2009
@@ -8,7 +8,7 @@
 util_driver_dir = %couchprivlibdir%
 max_document_size = 4294967296 ; 4 GB
 max_attachment_chunk_size = 4294967296 ; 4GB
-view_timeout = 5000 ; 5 seconds
+os_process_timeout = 5000 ; 5 seconds. for view and external servers.
 max_dbs_open = 100
 
 [httpd]
@@ -52,13 +52,16 @@
 _stats = {couch_httpd_stats_handlers, handle_stats_req}
 
 [httpd_db_handlers]
-_view = {couch_httpd_view, handle_view_req}
+_design = {couch_httpd_db, handle_design_req}
 _temp_view = {couch_httpd_view, handle_temp_view_req}
-_show = {couch_httpd_show, handle_doc_show_req}
-_list = {couch_httpd_show, handle_view_list_req}
 
 ; The external module takes an optional argument allowing you to narrow it to a
 ; single script. Otherwise the script name is inferred from the first path section 
 ; after _external's own path.
 ; _mypath = {couch_httpd_external, handle_external_req, <<"mykey">>}
 ; _external = {couch_httpd_external, handle_external_req}
+
+[httpd_design_handlers]
+_view = {couch_httpd_view, handle_view_req}
+_show = {couch_httpd_show, handle_doc_show_req}
+_list = {couch_httpd_show, handle_view_list_req}

Propchange: couchdb/branches/rep_security/etc/default/couchdb
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Fri Mar 13 21:12:44 2009
@@ -1,3 +1,4 @@
+/couchdb/branches/design_resources/etc/default/couchdb:751716-751803
 /couchdb/branches/form/etc/default/couchdb:729440-730015
-/couchdb/trunk/etc/default/couchdb:741843-750305
+/couchdb/trunk/etc/default/couchdb:741843-753015
 /incubator/couchdb/trunk/etc/default/couchdb:642419-694440

Modified: couchdb/branches/rep_security/share/server/main.js
URL: http://svn.apache.org/viewvc/couchdb/branches/rep_security/share/server/main.js?rev=753413&r1=753412&r2=753413&view=diff
==============================================================================
--- couchdb/branches/rep_security/share/server/main.js [utf-8] (original)
+++ couchdb/branches/rep_security/share/server/main.js [utf-8] Fri Mar 13 21:12:44 2009
@@ -364,10 +364,9 @@
         var row_info = row_line[listFun];
         runRenderFunction(listFun, [null, row, req, row_info]);
         if (row_info.first_key == null) {
-            row_info.first_key = row.key;
-        } else {
-            row_info.prev_key = row.key;
+          row_info.first_key = row.key;
         }
+        row_info.prev_key = row.key;
         row_info.row_number++;
         row_line[listFun] = row_info;
         break;

Modified: couchdb/branches/rep_security/share/www/database.html
URL: http://svn.apache.org/viewvc/couchdb/branches/rep_security/share/www/database.html?rev=753413&r1=753412&r2=753413&view=diff
==============================================================================
--- couchdb/branches/rep_security/share/www/database.html [utf-8] (original)
+++ couchdb/branches/rep_security/share/www/database.html [utf-8] Fri Mar 13 21:12:44 2009
@@ -39,7 +39,12 @@
       $(function() {
         if (page.redirecting) return;
         $("h1 strong").text(page.db.name);
-        var viewPath = (page.viewName || "_all_docs").replace(/^_design\//, "_view/");
+        var viewPath = page.viewName || "_all_docs";
+        if (/^_design\//.test(viewPath)) {
+          var parts = viewPath.split("/");
+          parts.splice(2, 0, "_view");
+          viewPath = parts.join("/");
+        }
         if (viewPath != "_temp_view" && viewPath != "_design_docs") {
           $("h1 a.raw").attr("href", "/" + encodeURIComponent(page.db.name) +
             "/" + viewPath);

Modified: couchdb/branches/rep_security/share/www/index.html
URL: http://svn.apache.org/viewvc/couchdb/branches/rep_security/share/www/index.html?rev=753413&r1=753412&r2=753413&view=diff
==============================================================================
--- couchdb/branches/rep_security/share/www/index.html [utf-8] (original)
+++ couchdb/branches/rep_security/share/www/index.html [utf-8] Fri Mar 13 21:12:44 2009
@@ -63,7 +63,6 @@
             <tr>
               <th>Name</th>
               <th class="size">Size</th>
-              <th class="apps">Applications</th>
               <th class="count">Number of Documents</th>
               <th class="seq">Update Seq</th>
             </tr>

Modified: couchdb/branches/rep_security/share/www/script/couch.js
URL: http://svn.apache.org/viewvc/couchdb/branches/rep_security/share/www/script/couch.js?rev=753413&r1=753412&r2=753413&view=diff
==============================================================================
--- couchdb/branches/rep_security/share/www/script/couch.js [utf-8] (original)
+++ couchdb/branches/rep_security/share/www/script/couch.js [utf-8] Fri Mar 13 21:12:44 2009
@@ -153,12 +153,13 @@
   }
 
   this.view = function(viewname, options, keys) {
+    var viewParts = viewname.split('/');
+    var viewPath = this.uri + "_design/" + viewParts[0] + "/_view/" 
+        + viewParts[1] + encodeOptions(options);
     if(!keys) {
-      this.last_req = this.request("GET", this.uri + "_view/" +
-          viewname + encodeOptions(options));      
+      this.last_req = this.request("GET", viewPath);      
     } else {
-      this.last_req = this.request("POST", this.uri + "_view/" + 
-        viewname + encodeOptions(options), {
+      this.last_req = this.request("POST", viewPath, {
         headers: {"Content-Type": "application/json"},
         body: JSON.stringify({keys:keys})
       });      
@@ -310,10 +311,9 @@
 CouchDB.replicate = function(source, target, rep_options) {
   rep_options = rep_options || {};
   var headers = rep_options.headers || {};
-  var options = rep_options.options || {};
   CouchDB.last_req = CouchDB.request("POST", "/_replicate", {
     headers: headers,
-    body: JSON.stringify({source: source, target: target, options: options})
+    body: JSON.stringify({source: source, target: target})
   });
   CouchDB.maybeThrowError(CouchDB.last_req);
   return JSON.parse(CouchDB.last_req.responseText);

Modified: couchdb/branches/rep_security/share/www/script/couch_tests.js
URL: http://svn.apache.org/viewvc/couchdb/branches/rep_security/share/www/script/couch_tests.js?rev=753413&r1=753412&r2=753413&view=diff
==============================================================================
--- couchdb/branches/rep_security/share/www/script/couch_tests.js [utf-8] (original)
+++ couchdb/branches/rep_security/share/www/script/couch_tests.js [utf-8] Fri Mar 13 21:12:44 2009
@@ -41,6 +41,7 @@
 loadTest("large_docs.js");
 loadTest("utf8.js");
 loadTest("attachments.js");
+loadTest("attachment_names.js");
 loadTest("attachment_paths.js");
 loadTest("attachment_views.js");
 loadTest("design_paths.js");

Modified: couchdb/branches/rep_security/share/www/script/futon.browse.js
URL: http://svn.apache.org/viewvc/couchdb/branches/rep_security/share/www/script/futon.browse.js?rev=753413&r1=753412&r2=753413&view=diff
==============================================================================
--- couchdb/branches/rep_security/share/www/script/futon.browse.js [utf-8] (original)
+++ couchdb/branches/rep_security/share/www/script/futon.browse.js [utf-8] Fri Mar 13 21:12:44 2009
@@ -52,16 +52,9 @@
               $("#databases tbody.content").append("<tr>" + 
                 "<th><a href='database.html?" + encodeURIComponent(dbName) + "'>" +
                   dbName + "</a></th>" +
-                "<td class='size'></td><td class='apps'></td><td class='count'></td>" +
+                "<td class='size'></td><td class='count'></td>" +
                 "<td class='seq'></td></tr>");
-              var db = $.couch.db(dbName);
-              db.allApps({
-                eachApp : function(name, path) {
-                  $("#databases tbody.content tr:eq(" + idx + ")")
-                    .find("td.apps").append('<a href="'+path+'">'+name+'</a> ');
-                }
-              });
-              db.info({
+              $.couch.db(dbName).info({
                 success: function(info) {
                   $("#databases tbody.content tr:eq(" + idx + ")")
                     .find("td.size").text($.futon.formatSize(info.disk_size)).end()

Modified: couchdb/branches/rep_security/share/www/script/jquery.couch.js
URL: http://svn.apache.org/viewvc/couchdb/branches/rep_security/share/www/script/jquery.couch.js?rev=753413&r1=753412&r2=753413&view=diff
==============================================================================
--- couchdb/branches/rep_security/share/www/script/jquery.couch.js [utf-8] (original)
+++ couchdb/branches/rep_security/share/www/script/jquery.couch.js [utf-8] Fri Mar 13 21:12:44 2009
@@ -191,9 +191,9 @@
                       appName = appName.join('/');
                       index = ddoc.couchapp && ddoc.couchapp.index;
                       if (index) {
-                        appPath = ['', name, index[0], appName, index[1]].join('/');
+                        appPath = ['', name, ddoc._id, index].join('/');
                       } else if (ddoc._attachments && ddoc._attachments["index.html"]) {
-                        appPath = ['', name, '_design', appName, "index.html"].join('/');
+                        appPath = ['', name, ddoc._id, "index.html"].join('/');
                       }
                       if (appPath) options.eachApp(appName, appPath, ddoc);
                     }
@@ -298,8 +298,9 @@
         },
         view: function(name, options) {
           options = options || {};
+          name = name.split('/');
           $.ajax({
-            type: "GET", url: this.uri + "_view/" + name + encodeOptions(options),
+            type: "GET", url: this.uri + "_design/" + name[0] + "/_view/" + name[1] + encodeOptions(options),
             dataType: "json",
             complete: function(req) {
               var resp = $.httpData(req, "json");

Propchange: couchdb/branches/rep_security/share/www/script/test/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Fri Mar 13 21:12:44 2009
@@ -0,0 +1 @@
+/couchdb/trunk/share/www/script/test:750306-753015

Copied: couchdb/branches/rep_security/share/www/script/test/attachment_names.js (from r753015, couchdb/trunk/share/www/script/test/attachment_names.js)
URL: http://svn.apache.org/viewvc/couchdb/branches/rep_security/share/www/script/test/attachment_names.js?p2=couchdb/branches/rep_security/share/www/script/test/attachment_names.js&p1=couchdb/trunk/share/www/script/test/attachment_names.js&r1=753015&r2=753413&rev=753413&view=diff
==============================================================================
--- couchdb/trunk/share/www/script/test/attachment_names.js (original)
+++ couchdb/branches/rep_security/share/www/script/test/attachment_names.js Fri Mar 13 21:12:44 2009
@@ -10,7 +10,7 @@
 // License for the specific language governing permissions and limitations under
 // the License.
 
-couchTests.attatchment_names = function(debug) { 
+couchTests.attachment_names = function(debug) { 
   var db = new CouchDB("test_suite_db"); 
   db.deleteDb(); 
   db.createDb(); 

Modified: couchdb/branches/rep_security/share/www/script/test/etags_views.js
URL: http://svn.apache.org/viewvc/couchdb/branches/rep_security/share/www/script/test/etags_views.js?rev=753413&r1=753412&r2=753413&view=diff
==============================================================================
--- couchdb/branches/rep_security/share/www/script/test/etags_views.js (original)
+++ couchdb/branches/rep_security/share/www/script/test/etags_views.js Fri Mar 13 21:12:44 2009
@@ -45,20 +45,20 @@
   db.bulkSave(docs);
   
   // verify get w/Etag on map view
-  xhr = CouchDB.request("GET", "/test_suite_db/_view/etags/basicView");
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/etags/_view/basicView");
   T(xhr.status == 200);
   var etag = xhr.getResponseHeader("etag");
-  xhr = CouchDB.request("GET", "/test_suite_db/_view/etags/basicView", {
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/etags/_view/basicView", {
     headers: {"if-none-match": etag}
   });
   T(xhr.status == 304);
   // TODO GET with keys (when that is available)
   
   // reduce view
-  xhr = CouchDB.request("GET", "/test_suite_db/_view/etags/withReduce");
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/etags/_view/withReduce");
   T(xhr.status == 200);
   var etag = xhr.getResponseHeader("etag");
-  xhr = CouchDB.request("GET", "/test_suite_db/_view/etags/withReduce", {
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/etags/_view/withReduce", {
     headers: {"if-none-match": etag}
   });
   T(xhr.status == 304);

Modified: couchdb/branches/rep_security/share/www/script/test/list_views.js
URL: http://svn.apache.org/viewvc/couchdb/branches/rep_security/share/www/script/test/list_views.js?rev=753413&r1=753412&r2=753413&view=diff
==============================================================================
--- couchdb/branches/rep_security/share/www/script/test/list_views.js (original)
+++ couchdb/branches/rep_security/share/www/script/test/list_views.js Fri Mar 13 21:12:44 2009
@@ -143,8 +143,8 @@
   T(view.total_rows == 10);
   
   // standard get
-  var xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/simpleForm/basicView");
-  T(xhr.status == 200);
+  var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/basicView");
+  T(xhr.status == 200, "standard get should be 200");
   T(/Total Rows/.test(xhr.responseText));
   T(/Key: 1/.test(xhr.responseText));
   T(/LineNo: 0/.test(xhr.responseText));
@@ -158,14 +158,14 @@
 
   // test that etags are available
   var etag = xhr.getResponseHeader("etag");
-  xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/simpleForm/basicView", {
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/basicView", {
     headers: {"if-none-match": etag}
   });
   T(xhr.status == 304);
 
   // get with query params
-  var xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/simpleForm/basicView?startkey=3");
-  T(xhr.status == 200);
+  var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/basicView?startkey=3");
+  T(xhr.status == 200, "with query params");
   T(/Total Rows/.test(xhr.responseText));
   T(!(/Key: 1/.test(xhr.responseText)));
   T(/FirstKey: 3/.test(xhr.responseText));
@@ -173,33 +173,33 @@
 
   
   // with 0 rows
-  var xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/simpleForm/basicView?startkey=30");
-  T(xhr.status == 200);
+  var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/basicView?startkey=30");
+  T(xhr.status == 200, "0 rows");
   T(/Total Rows/.test(xhr.responseText));
   T(/Offset: null/.test(xhr.responseText));
 
   // reduce with 0 rows
-  var xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/simpleForm/withReduce?startkey=30");
-  T(xhr.status == 200);
+  var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/withReduce?startkey=30");
+  T(xhr.status == 200, "reduce 0 rows");
   T(/Total Rows/.test(xhr.responseText));
   T(/Offset: undefined/.test(xhr.responseText));
 
   
   // when there is a reduce present, but not used
-  var xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/simpleForm/withReduce?reduce=false");
-  T(xhr.status == 200);
+  var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/withReduce?reduce=false");
+  T(xhr.status == 200, "reduce false");
   T(/Total Rows/.test(xhr.responseText));
   T(/Key: 1/.test(xhr.responseText));
   
   // when there is a reduce present, and used
-  xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/simpleForm/withReduce?group=true");
-  T(xhr.status == 200);
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/withReduce?group=true");
+  T(xhr.status == 200, "group reduce");
   T(/Key: 1/.test(xhr.responseText));
   
   // there should be etags on reduce as well
   var etag = xhr.getResponseHeader("etag");
   T(etag, "Etags should be served with reduce lists");
-  xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/simpleForm/withReduce?group=true", {
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/withReduce?group=true", {
     headers: {"if-none-match": etag}
   });
   T(xhr.status == 304);
@@ -208,13 +208,13 @@
   var docs = makeDocs(11, 12);
   db.bulkSave(docs);
   
-  xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/simpleForm/withReduce?group=true", {
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/withReduce?group=true", {
     headers: {"if-none-match": etag}
   });
-  T(xhr.status == 200);
+  T(xhr.status == 200, "reduce etag");
   
   // with accept headers for HTML
-  xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/acceptSwitch/basicView", {
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/acceptSwitch/basicView", {
     headers: {
       "Accept": 'text/html'
     }
@@ -224,7 +224,7 @@
   T(xhr.responseText.match(/Value/));
 
   // now with xml
-  xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/acceptSwitch/basicView", {
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/acceptSwitch/basicView", {
     headers: {
       "Accept": 'application/xml'
     }
@@ -234,25 +234,42 @@
   T(xhr.responseText.match(/entry/));
 
   // now with extra qs params
-  var xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/qsParams/basicView?foo=blam");
+  var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/qsParams/basicView?foo=blam");
   T(xhr.responseText.match(/blam/));
   
   // aborting iteration
-  var xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/stopIter/basicView");
+  var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/stopIter/basicView");
   T(xhr.responseText.match(/^head 0 1 2 tail$/));
-  xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/stopIter2/basicView");
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/stopIter2/basicView");
   T(xhr.responseText.match(/^head 0 1 2 tail$/));
 
   // aborting iteration with reduce
-  var xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/stopIter/withReduce?group=true");
+  var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/stopIter/withReduce?group=true");
   T(xhr.responseText.match(/^head 0 1 2 tail$/));
-  xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/stopIter2/withReduce?group=true");
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/stopIter2/withReduce?group=true");
   T(xhr.responseText.match(/^head 0 1 2 tail$/));
 
   // empty list
-  var xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/emptyList/basicView");
+  var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/emptyList/basicView");
   T(xhr.responseText.match(/^$/));
-  xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/emptyList/withReduce?group=true");
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/emptyList/withReduce?group=true");
   T(xhr.responseText.match(/^$/));
 
+  // multi-key fetch
+  var xhr = CouchDB.request("POST", "/test_suite_db/_design/lists/_list/simpleForm/basicView", {
+    body: '{"keys":[2,4,5,7]}'
+  });
+  T(xhr.status == 200, "multi key");
+  T(/Total Rows/.test(xhr.responseText));
+  T(!(/Key: 1/.test(xhr.responseText)));
+  T(/Key: 2/.test(xhr.responseText));
+  T(/FirstKey: 2/.test(xhr.responseText));
+  T(/LastKey: 7/.test(xhr.responseText));
+
+  // no multi-key fetch allowed when group=false
+  xhr = CouchDB.request("POST", "/test_suite_db/_design/lists/_list/simpleForm/withReduce?group=false", {
+    body: '{"keys":[2,4,5,7]}'
+  });
+  T(xhr.status == 400);
+  T(/query_parse_error/.test(xhr.responseText));
 };

Modified: couchdb/branches/rep_security/share/www/script/test/replication.js
URL: http://svn.apache.org/viewvc/couchdb/branches/rep_security/share/www/script/test/replication.js?rev=753413&r1=753412&r2=753413&view=diff
==============================================================================
--- couchdb/branches/rep_security/share/www/script/test/replication.js (original)
+++ couchdb/branches/rep_security/share/www/script/test/replication.js Fri Mar 13 21:12:44 2009
@@ -230,15 +230,5 @@
     result2 = CouchDB.replicate(B, A);
     T(result2.no_changes == true);
     T(result2.session_id == result.session_id);
-    
-    // do a full (not incremental) replication
-    
-    result = CouchDB.replicate(B, A, {options:{full:true}})
-    
-    T(0 == result.history[0].start_last_seq);
-    T(seqB == result.source_last_seq);
-    T(result.history[0].end_last_seq == seqB);
-    T(result.history[1].end_last_seq == seqB);
-    
   }
 };

Modified: couchdb/branches/rep_security/share/www/script/test/show_documents.js
URL: http://svn.apache.org/viewvc/couchdb/branches/rep_security/share/www/script/test/show_documents.js?rev=753413&r1=753412&r2=753413&view=diff
==============================================================================
--- couchdb/branches/rep_security/share/www/script/test/show_documents.js (original)
+++ couchdb/branches/rep_security/share/www/script/test/show_documents.js Fri Mar 13 21:12:44 2009
@@ -33,9 +33,16 @@
         }
       }),
       "just-name" : stringFun(function(doc, req) {
-        return {
-          body : "Just " + doc.name
-        };
+        if (doc) {
+          return {
+            body : "Just " + doc.name
+          };
+        } else {
+          return {
+            body : "No such doc",
+            code : 404
+          };
+        }
       }),
       "req-info" : stringFun(function(doc, req) {
         return {
@@ -123,68 +130,72 @@
   var docid = resp.id;
 
   // show error
-  var xhr = CouchDB.request("GET", "/test_suite_db/_show/");
-  T(xhr.status == 404);
+  var xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/");
+  T(xhr.status == 404, 'Should be missing');
   T(JSON.parse(xhr.responseText).reason == "Invalid path.");
   
   // hello template world
-  xhr = CouchDB.request("GET", "/test_suite_db/_show/template/hello/"+docid);
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/hello/"+docid);
   T(xhr.responseText == "Hello World");
  
   // hello template world (no docid)
-  xhr = CouchDB.request("GET", "/test_suite_db/_show/template/hello/");
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/hello");
   T(xhr.responseText == "Empty World");
 
   // // hello template world (non-existing docid)
-  xhr = CouchDB.request("GET", "/test_suite_db/_show/template/hello/nonExistingDoc");
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/hello/nonExistingDoc");
   T(xhr.responseText == "New World");
   
   // show with doc
-  xhr = CouchDB.request("GET", "/test_suite_db/_show/template/just-name/"+docid);
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/just-name/"+docid);
   T(xhr.responseText == "Just Rusty");
   
+  // show with missing doc
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/just-name/missingdoc");
+
+  T(xhr.status == 404, 'Doc should be missing');
+  T(xhr.responseText == "No such doc");
   
   // show with missing func
-  xhr = CouchDB.request("GET", "/test_suite_db/_show/template/missing/"+docid);
-  T(xhr.status == 404);
-
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/missing/"+docid);
+  T(xhr.status == 404, "function is missing");
+  
   // missing design doc
-  xhr = CouchDB.request("GET", "/test_suite_db/_show/missingdoc/just-name/"+docid);
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/missingddoc/_show/just-name/"+docid);
   T(xhr.status == 404);
   var resp = JSON.parse(xhr.responseText);
   T(resp.error == "not_found");
 
   // query parameters
-  xhr = CouchDB.request("GET", "/test_suite_db/_show/template/req-info/"+docid+"?foo=bar", {
-   headers: {
-     "Accept": "text/html;text/plain;*/*",
-     "X-Foo" : "bar"
-   }
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/req-info/"+docid+"?foo=bar", {
+    headers: {
+      "Accept": "text/html;text/plain;*/*",
+      "X-Foo" : "bar"
+    }
   });
   var resp = JSON.parse(xhr.responseText);
   T(equals(resp.headers["X-Foo"], "bar"));
   T(equals(resp.query, {foo:"bar"}));
   T(equals(resp.verb, "GET"));
-  T(equals(resp.path[4], docid));
+  T(equals(resp.path[5], docid));
   T(equals(resp.info.db_name, "test_suite_db"));
 
   // returning a content-type
-  xhr = CouchDB.request("GET", "/test_suite_db/_show/template/xml-type/"+docid);
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/xml-type/"+docid);
   T("application/xml" == xhr.getResponseHeader("Content-Type"));
   T("Accept" == xhr.getResponseHeader("Vary"));
 
   // accept header switching
-  // different mime has different etag
-
-  xhr = CouchDB.request("GET", "/test_suite_db/_show/template/accept-switch/"+docid, {
-   headers: {"Accept": "text/html;text/plain;*/*"}
+  // different mime has different etag  
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/accept-switch/"+docid, {
+    headers: {"Accept": "text/html;text/plain;*/*"}
   });
   T("text/html" == xhr.getResponseHeader("Content-Type"));
   T("Accept" == xhr.getResponseHeader("Vary"));
   var etag = xhr.getResponseHeader("etag");
 
-  xhr = CouchDB.request("GET", "/test_suite_db/_show/template/accept-switch/"+docid, {
-   headers: {"Accept": "image/png;*/*"}
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/accept-switch/"+docid, {
+    headers: {"Accept": "image/png;*/*"}
   });
   T(xhr.responseText.match(/PNG/))
   T("image/png" == xhr.getResponseHeader("Content-Type"));
@@ -193,12 +204,12 @@
 
   // proper etags
   // show with doc
-  xhr = CouchDB.request("GET", "/test_suite_db/_show/template/just-name/"+docid);
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/just-name/"+docid);
   // extract the ETag header values
   etag = xhr.getResponseHeader("etag");
   // get again with etag in request
-  xhr = CouchDB.request("GET", "/test_suite_db/_show/template/just-name/"+docid, {
-   headers: {"if-none-match": etag}
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/just-name/"+docid, {
+    headers: {"if-none-match": etag}
   });
   // should be 304
   T(xhr.status == 304);    
@@ -208,16 +219,16 @@
   resp = db.save(doc);
   T(resp.ok);
   // req with same etag
-  xhr = CouchDB.request("GET", "/test_suite_db/_show/template/just-name/"+docid, {
-   headers: {"if-none-match": etag}
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/just-name/"+docid, {
+    headers: {"if-none-match": etag}
   });
   // status is 200    
   T(xhr.status == 200);
 
   // get new etag and request again
   etag = xhr.getResponseHeader("etag");
-  xhr = CouchDB.request("GET", "/test_suite_db/_show/template/just-name/"+docid, {
-   headers: {"if-none-match": etag}
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/just-name/"+docid, {
+    headers: {"if-none-match": etag}
   });
   // should be 304
   T(xhr.status == 304);
@@ -225,9 +236,9 @@
   // update design doc (but not function)
   designDoc.isChanged = true;
   T(db.save(designDoc).ok);
-
-  xhr = CouchDB.request("GET", "/test_suite_db/_show/template/just-name/"+docid, {
-   headers: {"if-none-match": etag}
+  
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/just-name/"+docid, {
+    headers: {"if-none-match": etag}
   });
   // should be 304
   T(xhr.status == 304);
@@ -240,49 +251,49 @@
   }).toString();
   T(db.save(designDoc).ok);
 
-  xhr = CouchDB.request("GET", "/test_suite_db/_show/template/just-name/"+docid, {
-   headers: {"if-none-match": etag}
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/just-name/"+docid, {
+    headers: {"if-none-match": etag}
   });
   // status is 200    
   T(xhr.status == 200);
 
 
   // JS can't set etag
-  xhr = CouchDB.request("GET", "/test_suite_db/_show/template/no-set-etag/"+docid);
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/no-set-etag/"+docid);
   // extract the ETag header values
   etag = xhr.getResponseHeader("etag");
   T(etag != "skipped")
 
   // test the respondWith mime matcher
-  xhr = CouchDB.request("GET", "/test_suite_db/_show/template/respondWith/"+docid, {
-   headers: {
-     "Accept": 'text/html,application/atom+xml; q=0.9'
-   }
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/respondWith/"+docid, {
+    headers: {
+      "Accept": 'text/html,application/atom+xml; q=0.9'
+    }
   });
   T(xhr.getResponseHeader("Content-Type") == "text/html");
   T(xhr.responseText == "Ha ha, you said \"plankton\".");
 
   // now with xml
-  xhr = CouchDB.request("GET", "/test_suite_db/_show/template/respondWith/"+docid, {
-   headers: {
-     "Accept": 'application/xml'
-   }
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/respondWith/"+docid, {
+    headers: {
+      "Accept": 'application/xml'
+    }
   });
   T(xhr.getResponseHeader("Content-Type") == "application/xml");
   T(xhr.responseText.match(/node/));
   T(xhr.responseText.match(/plankton/));
 
   // registering types works
-  xhr = CouchDB.request("GET", "/test_suite_db/_show/template/respondWith/"+docid, {
-   headers: {
-     "Accept": "application/x-foo"
-   }
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/respondWith/"+docid, {
+    headers: {
+      "Accept": "application/x-foo"
+    }
   });
   T(xhr.getResponseHeader("Content-Type") == "application/x-foo");
   T(xhr.responseText.match(/foofoo/));
 
   // test the respondWith mime matcher without
-  xhr = CouchDB.request("GET", "/test_suite_db/_show/template/respondWith/"+docid, {
+  xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/respondWith/"+docid, {
    headers: {
      "Accept": 'text/html,application/atom+xml; q=0.9'
    }

Modified: couchdb/branches/rep_security/share/www/style/layout.css
URL: http://svn.apache.org/viewvc/couchdb/branches/rep_security/share/www/style/layout.css?rev=753413&r1=753412&r2=753413&view=diff
==============================================================================
--- couchdb/branches/rep_security/share/www/style/layout.css (original)
+++ couchdb/branches/rep_security/share/www/style/layout.css Fri Mar 13 21:12:44 2009
@@ -336,8 +336,8 @@
 
 /* Database table */
 
-#databases thead th.apps, #databases thead th.size, #databases thead th.count, #databases thead th.seq,
-#databases thead th.apps, #databases tbody td.size, #databases tbody td.count, #databases tbody td.seq {
+#databases thead th.size, #databases thead th.count, #databases thead th.seq,
+#databases tbody td.size, #databases tbody td.count, #databases tbody td.seq {
   text-align: right;
 }
 

Modified: couchdb/branches/rep_security/src/couchdb/Makefile.am
URL: http://svn.apache.org/viewvc/couchdb/branches/rep_security/src/couchdb/Makefile.am?rev=753413&r1=753412&r2=753413&view=diff
==============================================================================
--- couchdb/branches/rep_security/src/couchdb/Makefile.am (original)
+++ couchdb/branches/rep_security/src/couchdb/Makefile.am Fri Mar 13 21:12:44 2009
@@ -64,6 +64,7 @@
     couch_query_servers.erl \
     couch_ref_counter.erl \
     couch_rep.erl \
+    couch_rep_sup.erl \
     couch_server.erl \
     couch_server_sup.erl \
     couch_stats_aggregator.erl \
@@ -104,6 +105,7 @@
     couch_query_servers.beam \
     couch_ref_counter.beam \
     couch_rep.beam \
+    couch_rep_sup.beam \
     couch_server.beam \
     couch_server_sup.beam \
     couch_stats_aggregator.beam \
@@ -139,6 +141,7 @@
 #     couch_log.html \
 #     couch_query_servers.html \
 #     couch_rep.html \
+#     couch_rep_sup.html \
 #     couch_server.html \
 #     couch_server_sup.html \
 #     couch_stream.html \

Modified: couchdb/branches/rep_security/src/couchdb/couch_db.hrl
URL: http://svn.apache.org/viewvc/couchdb/branches/rep_security/src/couchdb/couch_db.hrl?rev=753413&r1=753412&r2=753413&view=diff
==============================================================================
--- couchdb/branches/rep_security/src/couchdb/couch_db.hrl (original)
+++ couchdb/branches/rep_security/src/couchdb/couch_db.hrl Fri Mar 13 21:12:44 2009
@@ -60,7 +60,9 @@
     method,
     path_parts,
     db_url_handlers,
-    user_ctx
+    user_ctx,
+    req_body = undefined,
+    design_url_handlers
     }).
     
 

Modified: couchdb/branches/rep_security/src/couchdb/couch_doc.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/rep_security/src/couchdb/couch_doc.erl?rev=753413&r1=753412&r2=753413&view=diff
==============================================================================
--- couchdb/branches/rep_security/src/couchdb/couch_doc.erl (original)
+++ couchdb/branches/rep_security/src/couchdb/couch_doc.erl Fri Mar 13 21:12:44 2009
@@ -63,7 +63,13 @@
 
 to_json_attachment_stubs(Attachments) ->
     BinProps = lists:map(
-        fun({Name, {Type, BinValue}}) ->
+        fun({Name, {Type, {_RcvFun, Length}}}) ->
+            {Name, {[
+                {<<"stub">>, true},
+                {<<"content_type">>, Type},
+                {<<"length">>, Length}
+            ]}};
+        ({Name, {Type, BinValue}}) ->
             {Name, {[
                 {<<"stub">>, true},
                 {<<"content_type">>, Type},
@@ -78,7 +84,13 @@
 
 to_json_attachments(Attachments) ->
     BinProps = lists:map(
-        fun({Name, {Type, BinValue}}) ->
+        fun({Name, {Type, {RcvFun, Length}}}) ->
+            Data = read_streamed_attachment(RcvFun, Length, _Acc = []),
+            {Name, {[
+                {<<"content_type">>, Type},
+                {<<"data">>, couch_util:encodeBase64(Data)}
+            ]}};
+        ({Name, {Type, BinValue}}) ->
             {Name, {[
                 {<<"content_type">>, Type},
                 {<<"data">>, couch_util:encodeBase64(bin_to_binary(BinValue))}
@@ -157,7 +169,9 @@
     Bins = lists:flatmap(fun({Name, {BinProps}}) ->
         case proplists:get_value(<<"stub">>, BinProps) of
         true ->
-            [{Name, stub}];
+            Type = proplists:get_value(<<"content_type">>, BinProps),
+            Length = proplists:get_value(<<"length">>, BinProps),
+            [{Name, {stub, Type, Length}}];
         _ ->
             Value = proplists:get_value(<<"data">>, BinProps),
             Type = proplists:get_value(<<"content_type">>, BinProps,
@@ -270,7 +284,7 @@
     has_stubs(Bins);
 has_stubs([]) ->
     false;
-has_stubs([{_Name, stub}|_]) ->
+has_stubs([{_Name, {stub, _, _}}|_]) ->
     true;
 has_stubs([_Bin|Rest]) ->
     has_stubs(Rest).
@@ -278,9 +292,15 @@
 merge_stubs(#doc{attachments=MemBins}=StubsDoc, #doc{attachments=DiskBins}) ->
     BinDict = dict:from_list(DiskBins),
     MergedBins = lists:map(
-        fun({Name, stub}) ->
+        fun({Name, {stub, _, _}}) ->
             {Name, dict:fetch(Name, BinDict)};
         ({Name, Value}) ->
             {Name, Value}
         end, MemBins),
     StubsDoc#doc{attachments= MergedBins}.
+
+read_streamed_attachment(_RcvFun, 0, Acc) ->
+    list_to_binary(lists:reverse(Acc));
+read_streamed_attachment(RcvFun, LenLeft, Acc) ->
+    Bin = RcvFun(),
+    read_streamed_attachment(RcvFun, LenLeft - size(Bin), [Bin|Acc]).

Modified: couchdb/branches/rep_security/src/couchdb/couch_external_server.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/rep_security/src/couchdb/couch_external_server.erl?rev=753413&r1=753412&r2=753413&view=diff
==============================================================================
--- couchdb/branches/rep_security/src/couchdb/couch_external_server.erl (original)
+++ couchdb/branches/rep_security/src/couchdb/couch_external_server.erl Fri Mar 13 21:12:44 2009
@@ -27,7 +27,7 @@
     gen_server:cast(Pid, stop).
 
 execute(Pid, JsonReq) ->
-    gen_server:call(Pid, {execute, JsonReq}).
+    gen_server:call(Pid, {execute, JsonReq}, infinity).
 
 % Gen Server Handlers
 

Modified: couchdb/branches/rep_security/src/couchdb/couch_httpd.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/rep_security/src/couchdb/couch_httpd.erl?rev=753413&r1=753412&r2=753413&view=diff
==============================================================================
--- couchdb/branches/rep_security/src/couchdb/couch_httpd.erl (original)
+++ couchdb/branches/rep_security/src/couchdb/couch_httpd.erl Fri Mar 13 21:12:44 2009
@@ -13,7 +13,7 @@
 -module(couch_httpd).
 -include("couch_db.hrl").
 
--export([start_link/0, stop/0, handle_request/3]).
+-export([start_link/0, stop/0, handle_request/4]).
 
 -export([header_value/2,header_value/3,qs_value/2,qs_value/3,qs/1,path/1,absolute_uri/2]).
 -export([verify_is_server_admin/1,unquote/1,quote/1,recv/2,recv_chunked/4,error_info/1]).
@@ -44,11 +44,18 @@
         fun({UrlKey, SpecStr}) ->
             {?l2b(UrlKey), make_arity_2_fun(SpecStr)}
         end, couch_config:get("httpd_db_handlers")),
+
+    DesignUrlHandlersList = lists:map(
+        fun({UrlKey, SpecStr}) ->
+            {?l2b(UrlKey), make_arity_2_fun(SpecStr)}
+        end, couch_config:get("httpd_design_handlers")),
+        
     UrlHandlers = dict:from_list(UrlHandlersList),
     DbUrlHandlers = dict:from_list(DbUrlHandlersList),
+    DesignUrlHandlers = dict:from_list(DesignUrlHandlersList),
     Loop = fun(Req)->
             apply(?MODULE, handle_request,
-                    [Req, UrlHandlers, DbUrlHandlers])
+                    [Req, UrlHandlers, DbUrlHandlers, DesignUrlHandlers])
         end,
 
     % and off we go
@@ -101,7 +108,7 @@
     mochiweb_http:stop(?MODULE).
     
 
-handle_request(MochiReq, UrlHandlers, DbUrlHandlers) ->
+handle_request(MochiReq, UrlHandlers, DbUrlHandlers, DesignUrlHandlers) ->
     statistics(runtime), % prepare request_time counter, see end of function
     AuthenticationFun = make_arity_1_fun(
             couch_config:get("httpd", "authentication_handler")),
@@ -147,7 +154,8 @@
         method = Method,
         path_parts = [list_to_binary(couch_httpd:unquote(Part))
                 || Part <- string:tokens(Path, "/")],
-        db_url_handlers = DbUrlHandlers
+        db_url_handlers = DbUrlHandlers,
+        design_url_handlers = DesignUrlHandlers
         },
     DefaultFun = fun couch_httpd_db:handle_request/1,
     HandlerFun = couch_util:dict_find(HandlerKey, UrlHandlers, DefaultFun),
@@ -347,7 +355,7 @@
 send_response(#httpd{mochi_req=MochiReq}, Code, Headers, Body) ->
     couch_stats_collector:increment({httpd_status_codes, Code}),
     if Code >= 400 ->
-        ?LOG_DEBUG("HTTPd ~p error response:~n ~s", [Code, Body]);
+        ?LOG_DEBUG("httpd ~p error response:~n ~s", [Code, Body]);
     true -> ok
     end,
     {ok, MochiReq:respond({Code, Headers ++ server_header(), Body})}.
@@ -384,11 +392,12 @@
     send_chunk(Resp, []).
 
 
-
 error_info(bad_request) ->
     {400, <<"bad_request">>, <<>>};
 error_info({bad_request, Reason}) ->
     {400, <<"bad_request">>, Reason};
+error_info({query_parse_error, Reason}) ->
+    {400, <<"query_parse_error">>, Reason};
 error_info(not_found) ->
     {404, <<"not_found">>, <<"Missing">>};
 error_info({not_found, Reason}) ->

Modified: couchdb/branches/rep_security/src/couchdb/couch_httpd_db.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/rep_security/src/couchdb/couch_httpd_db.erl?rev=753413&r1=753412&r2=753413&view=diff
==============================================================================
--- couchdb/branches/rep_security/src/couchdb/couch_httpd_db.erl (original)
+++ couchdb/branches/rep_security/src/couchdb/couch_httpd_db.erl Fri Mar 13 21:12:44 2009
@@ -13,7 +13,7 @@
 -module(couch_httpd_db).
 -include("couch_db.hrl").
 
--export([handle_request/1, db_req/2, couch_doc_open/4]).
+-export([handle_request/1, handle_design_req/2, db_req/2, couch_doc_open/4]).
 
 -import(couch_httpd,
     [send_json/2,send_json/3,send_json/4,send_method_not_allowed/2,
@@ -41,6 +41,16 @@
         do_db_req(Req, Handler)
     end.
 
+handle_design_req(#httpd{
+        path_parts=[_DbName,_Design,_DesName, <<"_",_/binary>> = Action | _Rest],
+        design_url_handlers = DesignUrlHandlers
+    }=Req, Db) ->
+    Handler = couch_util:dict_find(Action, DesignUrlHandlers, fun db_req/2),
+    Handler(Req, Db);
+    
+handle_design_req(Req, Db) ->
+    db_req(Req, Db).
+
 create_db_req(#httpd{user_ctx=UserCtx}=Req, DbName) ->
     ok = couch_httpd:verify_is_server_admin(Req),
     case couch_server:create(DbName, [{user_ctx, UserCtx}]) of
@@ -116,6 +126,7 @@
         Docs = lists:map(
             fun({ObjProps} = JsonObj) ->
                 Doc = couch_doc:from_json_obj(JsonObj),
+                validate_attachment_names(Doc),
                 Id = case Doc#doc.id of
                     <<>> -> couch_util:new_uuid();
                     Id0 -> Id0
@@ -460,31 +471,6 @@
         end_json_response(Resp)
     end;
 
-db_doc_req(#httpd{method='POST'}=Req, Db, DocId) ->
-    Form = couch_httpd:parse_form(Req),
-    Rev = couch_doc:parse_rev(proplists:get_value("_rev", Form)),
-    Doc = case couch_db:open_doc_revs(Db, DocId, [Rev], []) of
-        {ok, [{ok, Doc0}]}  -> Doc0#doc{revs=[Rev]};
-        {ok, [Error]}       -> throw(Error)
-    end,
-
-    NewAttachments = [
-        {list_to_binary(Name), {list_to_binary(ContentType), Content}} ||
-        {Name, {ContentType, _}, Content} <-
-        proplists:get_all_values("_attachments", Form)
-    ],
-    #doc{attachments=Attachments} = Doc,
-    NewDoc = Doc#doc{
-        attachments = Attachments ++ NewAttachments
-    },
-    {ok, NewRev} = couch_db:update_doc(Db, NewDoc, []),
-
-    send_json(Req, 201, [{"Etag", "\"" ++ NewRev ++ "\""}], {obj, [
-        {ok, true},
-        {id, DocId},
-        {rev, NewRev}
-    ]});
-
 db_doc_req(#httpd{method='PUT'}=Req, Db, DocId) ->
     update_doc(Req, Db, DocId, couch_httpd:json_body(Req));
 
@@ -545,6 +531,7 @@
 
 update_doc(Req, Db, DocId, Json) ->
     #doc{deleted=Deleted} = Doc = couch_doc:from_json_obj(Json),
+    validate_attachment_names(Doc),
     ExplicitDocRev =
     case Doc#doc.revs of
         {Start,[RevId|_]} -> {Start, RevId};
@@ -629,8 +616,11 @@
 
 db_attachment_req(#httpd{method=Method}=Req, Db, DocId, FileNameParts)
         when (Method == 'PUT') or (Method == 'DELETE') ->
-    FileName = list_to_binary(mochiweb_util:join(lists:map(fun binary_to_list/1, 
-        FileNameParts),"/")),
+    FileName = validate_attachment_name(
+                    mochiweb_util:join(
+                        lists:map(fun binary_to_list/1, 
+                            FileNameParts),"/")),
+    
     NewAttachment = case Method of
         'DELETE' ->
             [];
@@ -746,3 +736,44 @@
         {list_to_binary(DocId), {Pos, [RevId]}}
     end.
 
+validate_attachment_names(Doc) ->
+    lists:foreach(fun({Name, _}) -> 
+        validate_attachment_name(Name)
+    end, Doc#doc.attachments).
+
+validate_attachment_name(Name) when is_list(Name) ->
+    validate_attachment_name(list_to_binary(Name));
+validate_attachment_name(<<"_",_/binary>>) ->
+    throw({bad_request, <<"Attachment name can't start with '_'">>});
+validate_attachment_name(Name) ->
+    case is_valid_utf8(Name) of
+        true -> Name;
+        false -> throw({bad_request, <<"Attachment name is not UTF-8 encoded">>})
+    end.
+
+%% borrowed from mochijson2:json_bin_is_safe()
+is_valid_utf8(<<>>) ->
+    true;
+is_valid_utf8(<<C, Rest/binary>>) ->
+    case C of
+        $\" ->
+            false;
+        $\\ ->
+            false;
+        $\b ->
+            false;
+        $\f ->
+            false;
+        $\n ->
+            false;
+        $\r ->
+            false;
+        $\t ->
+            false;
+        C when C >= 0, C < $\s; C >= 16#7f, C =< 16#10FFFF ->
+            false;
+        C when C < 16#7f ->
+            is_valid_utf8(Rest);
+        _ ->
+            false
+    end.

Modified: couchdb/branches/rep_security/src/couchdb/couch_httpd_external.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/rep_security/src/couchdb/couch_httpd_external.erl?rev=753413&r1=753412&r2=753413&view=diff
==============================================================================
--- couchdb/branches/rep_security/src/couchdb/couch_httpd_external.erl (original)
+++ couchdb/branches/rep_security/src/couchdb/couch_httpd_external.erl Fri Mar 13 21:12:44 2009
@@ -56,9 +56,13 @@
 
 json_req_obj(#httpd{mochi_req=Req, 
                method=Verb,
-               path_parts=Path
+               path_parts=Path,
+               req_body=ReqBody
             }, Db) ->
-    ReqBody = Req:recv_body(),
+    Body = case ReqBody of
+        undefined -> Req:recv_body();
+        Else -> Else
+    end,
     ParsedForm = case Req:get_primary_header_value("content-type") of
         "application/x-www-form-urlencoded" ++ _ ->
             mochiweb_util:parse_qs(ReqBody);
@@ -74,7 +78,7 @@
         {<<"path">>, Path},
         {<<"query">>, to_json_terms(Req:parse_qs())},
         {<<"headers">>, to_json_terms(Hlist)},
-        {<<"body">>, ReqBody},
+        {<<"body">>, Body},
         {<<"form">>, to_json_terms(ParsedForm)},
         {<<"cookie">>, to_json_terms(Req:parse_cookie())}]}.
 

Modified: couchdb/branches/rep_security/src/couchdb/couch_httpd_misc_handlers.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/rep_security/src/couchdb/couch_httpd_misc_handlers.erl?rev=753413&r1=753412&r2=753413&view=diff
==============================================================================
--- couchdb/branches/rep_security/src/couchdb/couch_httpd_misc_handlers.erl (original)
+++ couchdb/branches/rep_security/src/couchdb/couch_httpd_misc_handlers.erl Fri Mar 13 21:12:44 2009
@@ -70,12 +70,12 @@
 handle_task_status_req(Req) ->
     send_method_not_allowed(Req, "GET,HEAD").
 
-% convert to list and add trailing slash if missing
+% add trailing slash if missing
 fix_db_url(UrlBin) ->
-    case lists:last(Url = ?b2l(UrlBin)) of
+    ?l2b(case lists:last(Url = ?b2l(UrlBin)) of
     $/ -> Url;
     _  -> Url ++ "/"
-    end.
+    end).
     
 
 get_rep_endpoint(_Req, {Props}) ->
@@ -91,12 +91,16 @@
 
 handle_replicate_req(#httpd{method='POST'}=Req) ->
     {Props} = couch_httpd:json_body(Req),
-    Src = get_rep_endpoint(Req, proplists:get_value(<<"source">>, Props)),
-    Tgt = get_rep_endpoint(Req, proplists:get_value(<<"target">>, Props)),
-    {OptionsBin} = proplists:get_value(<<"options">>, Props, {[]}),
-    Options = [{couch_util:to_existing_atom(K), V} || {K,V} <- OptionsBin],
-    {ok, {JsonResults}} = couch_rep:replicate(Src, Tgt, Options),
-    send_json(Req, {[{ok, true} | JsonResults]});
+    Source = get_rep_endpoint(Req, proplists:get_value(<<"source">>, Props)),
+    Target = get_rep_endpoint(Req, proplists:get_value(<<"target">>, Props)),
+    case couch_rep:replicate(Source, Target) of
+    {ok, {JsonResults}} ->
+        send_json(Req, {[{ok, true} | JsonResults]});
+    {error, {Type, Details}} ->
+        send_json(Req, 500, {[{error, Type}, {reason, Details}]});
+    {error, Reason} ->
+        send_json(Req, 500, {[{error, Reason}]})
+    end;
 handle_replicate_req(Req) ->
     send_method_not_allowed(Req, "POST").
 

Modified: couchdb/branches/rep_security/src/couchdb/couch_httpd_show.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/rep_security/src/couchdb/couch_httpd_show.erl?rev=753413&r1=753412&r2=753413&view=diff
==============================================================================
--- couchdb/branches/rep_security/src/couchdb/couch_httpd_show.erl (original)
+++ couchdb/branches/rep_security/src/couchdb/couch_httpd_show.erl Fri Mar 13 21:12:44 2009
@@ -24,7 +24,7 @@
     
 handle_doc_show_req(#httpd{
         method='GET',
-        path_parts=[_, _, DesignName, ShowName, DocId]
+        path_parts=[_DbName, _Design, DesignName, _Show, ShowName, DocId]
     }=Req, Db) ->
     DesignId = <<"_design/", DesignName/binary>>,
     #doc{body={Props}} = couch_httpd_db:couch_doc_open(Db, DesignId, nil, []),
@@ -39,7 +39,7 @@
 
 handle_doc_show_req(#httpd{
         method='GET',
-        path_parts=[_, _, DesignName, ShowName]
+        path_parts=[_DbName, _Design, DesignName, _Show, ShowName]
     }=Req, Db) ->
     DesignId = <<"_design/", DesignName/binary>>,
     #doc{body={Props}} = couch_httpd_db:couch_doc_open(Db, DesignId, nil, []),
@@ -53,18 +53,30 @@
 handle_doc_show_req(Req, _Db) ->
     send_method_not_allowed(Req, "GET,HEAD").
 
-handle_view_list_req(#httpd{method='GET',path_parts=[_, _, DesignName, ListName, ViewName]}=Req, Db) ->
+handle_view_list_req(#httpd{method='GET',
+        path_parts=[_DbName, _Design, DesignName, _List, ListName, ViewName]}=Req, Db) ->
     DesignId = <<"_design/", DesignName/binary>>,
     #doc{body={Props}} = couch_httpd_db:couch_doc_open(Db, DesignId, nil, []),
     Lang = proplists:get_value(<<"language">>, Props, <<"javascript">>),
     ListSrc = get_nested_json_value({Props}, [<<"lists">>, ListName]),
-    send_view_list_response(Lang, ListSrc, ViewName, DesignId, Req, Db);
+    send_view_list_response(Lang, ListSrc, ViewName, DesignId, Req, Db, nil);
 
 handle_view_list_req(#httpd{method='GET'}=Req, _Db) ->
     send_error(Req, 404, <<"list_error">>, <<"Invalid path.">>);
 
+handle_view_list_req(#httpd{method='POST',
+        path_parts=[_DbName, _Design, DesignName, _List, ListName, ViewName]}=Req, Db) ->
+    DesignId = <<"_design/", DesignName/binary>>,
+    #doc{body={Props}} = couch_httpd_db:couch_doc_open(Db, DesignId, [], []),
+    Lang = proplists:get_value(<<"language">>, Props, <<"javascript">>),
+    ListSrc = get_nested_json_value({Props}, [<<"lists">>, ListName]),
+    ReqBody = couch_httpd:body(Req),
+    {Props2} = ?JSON_DECODE(ReqBody),
+    Keys = proplists:get_value(<<"keys">>, Props2, nil),
+    send_view_list_response(Lang, ListSrc, ViewName, DesignId, Req#httpd{req_body=ReqBody}, Db, Keys);
+
 handle_view_list_req(Req, _Db) ->
-    send_method_not_allowed(Req, "GET,HEAD").
+    send_method_not_allowed(Req, "GET,POST,HEAD").
 
 
 get_nested_json_value({Props}, [Key|Keys]) ->
@@ -77,30 +89,71 @@
 get_nested_json_value(_NotJSONObj, _) ->
     throw({not_found, json_mismatch}).
 
-send_view_list_response(Lang, ListSrc, ViewName, DesignId, Req, Db) ->
+send_view_list_response(Lang, ListSrc, ViewName, DesignId, Req, Db, Keys) ->
     #view_query_args{
         stale = Stale,
         reduce = Reduce
     } = QueryArgs = couch_httpd_view:parse_view_query(Req, nil, nil, true),
     case couch_view:get_map_view(Db, DesignId, ViewName, Stale) of
     {ok, View, Group} ->    
-        output_map_list(Req, Lang, ListSrc, View, Group, Db, QueryArgs);
+        output_map_list(Req, Lang, ListSrc, View, Group, Db, QueryArgs, Keys);
     {not_found, _Reason} ->
         case couch_view:get_reduce_view(Db, DesignId, ViewName, Stale) of
         {ok, ReduceView, Group} ->
+            couch_httpd_view:parse_view_query(Req, Keys, true, true), % just for validation
             case Reduce of
             false ->
                 MapView = couch_view:extract_map_view(ReduceView),
-                output_map_list(Req, Lang, ListSrc, MapView, Group, Db, QueryArgs);
+                output_map_list(Req, Lang, ListSrc, MapView, Group, Db, QueryArgs, Keys);
             _ ->
-                output_reduce_list(Req, Lang, ListSrc, ReduceView, Group, Db, QueryArgs)
+                output_reduce_list(Req, Lang, ListSrc, ReduceView, Group, Db, QueryArgs, Keys)
             end;
         {not_found, Reason} ->
             throw({not_found, Reason})
         end
     end.
 
-output_map_list(#httpd{mochi_req=MReq}=Req, Lang, ListSrc, View, Group, Db, QueryArgs) ->
+make_map_start_resp_fun(QueryServer, Req, Db, CurrentEtag) ->
+    fun(Req2, _Etag, TotalViewCount, Offset) ->
+        ExternalResp = couch_query_servers:render_list_head(QueryServer, 
+            Req2, Db, TotalViewCount, Offset),
+        JsonResp = apply_etag(ExternalResp, CurrentEtag),
+        #extern_resp_args{
+            code = Code,
+            data = BeginBody,
+            ctype = CType,
+            headers = ExtHeaders
+        } = couch_httpd_external:parse_external_response(JsonResp),
+        JsonHeaders = couch_httpd_external:default_or_content_type(CType, ExtHeaders),
+        {ok, Resp} = start_chunked_response(Req, Code, JsonHeaders),
+        {ok, Resp, binary_to_list(BeginBody)}
+    end.
+
+make_map_send_row_fun(QueryServer, Req) ->
+    fun(Resp, Db2, {{Key, DocId}, Value}, 
+        RowFront, _IncludeDocs) ->
+        JsonResp = couch_query_servers:render_list_row(QueryServer, 
+            Req, Db2, {{Key, DocId}, Value}),
+        #extern_resp_args{
+            stop = StopIter,
+            data = RowBody
+        } = couch_httpd_external:parse_external_response(JsonResp),
+        case StopIter of
+        true -> stop;
+        _ ->
+            RowFront2 = case RowFront of
+            nil -> [];
+            _ -> RowFront
+            end,
+            Chunk = RowFront2 ++ binary_to_list(RowBody),
+            case Chunk of
+                [] -> {ok, Resp};
+                _ -> send_chunk(Resp, Chunk)
+            end
+        end
+    end.
+
+output_map_list(#httpd{mochi_req=MReq}=Req, Lang, ListSrc, View, Group, Db, QueryArgs, nil) ->
     #view_query_args{
         limit = Limit,
         direction = Dir,
@@ -119,43 +172,8 @@
         % pass it into the view fold with closures
         {ok, QueryServer} = couch_query_servers:start_view_list(Lang, ListSrc),
 
-        StartListRespFun = fun(Req2, _Etag, TotalViewCount, Offset) ->
-            ExternalResp = couch_query_servers:render_list_head(QueryServer, 
-                Req2, Db, TotalViewCount, Offset),
-            JsonResp = apply_etag(ExternalResp, CurrentEtag),
-            #extern_resp_args{
-                code = Code,
-                data = BeginBody,
-                ctype = CType,
-                headers = ExtHeaders
-            } = couch_httpd_external:parse_external_response(JsonResp),
-            JsonHeaders = couch_httpd_external:default_or_content_type(CType, ExtHeaders),
-            {ok, Resp} = start_chunked_response(Req, Code, JsonHeaders),
-            {ok, Resp, binary_to_list(BeginBody)}
-        end,
-    
-        SendListRowFun = fun(Resp, Db2, {{Key, DocId}, Value}, 
-            RowFront, _IncludeDocs) ->
-            JsonResp = couch_query_servers:render_list_row(QueryServer, 
-                Req, Db2, {{Key, DocId}, Value}),
-            #extern_resp_args{
-                stop = StopIter,
-                data = RowBody
-            } = couch_httpd_external:parse_external_response(JsonResp),
-            case StopIter of
-            true -> stop;
-            _ ->
-                RowFront2 = case RowFront of
-                nil -> [];
-                _ -> RowFront
-                end,
-                Chunk = RowFront2 ++ binary_to_list(RowBody),
-                case Chunk of
-                    [] -> {ok, Resp};
-                    _ -> send_chunk(Resp, Chunk)
-                end
-            end
-        end,
+        StartListRespFun = make_map_start_resp_fun(QueryServer, Req, Db, CurrentEtag),
+        SendListRowFun = make_map_send_row_fun(QueryServer, Req),
     
         FoldlFun = couch_httpd_view:make_view_fold_fun(Req, QueryArgs, CurrentEtag, Db, RowCount,
             #view_fold_helper_funs{
@@ -166,9 +184,85 @@
         FoldAccInit = {Limit, SkipCount, undefined, []},
         FoldResult = couch_view:fold(View, Start, Dir, FoldlFun, FoldAccInit),
         finish_list(Req, Db, QueryServer, CurrentEtag, FoldResult, StartListRespFun, RowCount)
+    end);
+
+output_map_list(#httpd{mochi_req=MReq}=Req, Lang, ListSrc, View, Group, Db, QueryArgs, Keys) ->
+    #view_query_args{
+        limit = Limit,
+        direction = Dir,
+        skip = SkipCount,
+        start_docid = StartDocId
+    } = QueryArgs,
+    {ok, RowCount} = couch_view:get_row_count(View),
+    Headers = MReq:get(headers),
+    Hlist = mochiweb_headers:to_list(Headers),
+    Accept = proplists:get_value('Accept', Hlist),
+    CurrentEtag = couch_httpd_view:view_group_etag(Group, {Lang, ListSrc, Accept}),
+    couch_httpd:etag_respond(Req, CurrentEtag, fun() ->
+        % get the os process here
+        % pass it into the view fold with closures
+        {ok, QueryServer} = couch_query_servers:start_view_list(Lang, ListSrc),
+
+        StartListRespFun = make_map_start_resp_fun(QueryServer, Req, Db, CurrentEtag),
+        SendListRowFun = make_map_send_row_fun(QueryServer, Req),
+
+        FoldAccInit = {Limit, SkipCount, undefined, []},
+        FoldResult = lists:foldl(
+            fun(Key, {ok, FoldAcc}) ->
+                FoldlFun = couch_httpd_view:make_view_fold_fun(Req, QueryArgs#view_query_args{
+                        start_key = Key,
+                        end_key = Key
+                    }, CurrentEtag, Db, RowCount,
+                    #view_fold_helper_funs{
+                        reduce_count = fun couch_view:reduce_to_count/1,
+                        start_response = StartListRespFun,
+                        send_row = SendListRowFun
+                    }),
+                couch_view:fold(View, {Key, StartDocId}, Dir, FoldlFun, FoldAcc)
+            end, {ok, FoldAccInit}, Keys),
+        finish_list(Req, Db, QueryServer, CurrentEtag, FoldResult, StartListRespFun, RowCount)
     end).
 
-output_reduce_list(#httpd{mochi_req=MReq}=Req, Lang, ListSrc, View, Group, Db, QueryArgs) ->
+make_reduce_start_resp_fun(QueryServer, Req, Db, CurrentEtag) ->
+    fun(Req2, _Etag, _, _) ->
+        JsonResp = couch_query_servers:render_reduce_head(QueryServer, 
+            Req2, Db),
+        JsonResp2 = apply_etag(JsonResp, CurrentEtag),
+        #extern_resp_args{
+            code = Code,
+            data = BeginBody,
+            ctype = CType,
+            headers = ExtHeaders
+        } = couch_httpd_external:parse_external_response(JsonResp2),
+        JsonHeaders = couch_httpd_external:default_or_content_type(CType, ExtHeaders),
+        {ok, Resp} = start_chunked_response(Req, Code, JsonHeaders),
+        {ok, Resp, binary_to_list(BeginBody)}
+    end.
+
+make_reduce_send_row_fun(QueryServer, Req, Db) ->
+    fun(Resp, {Key, Value}, RowFront) ->
+        JsonResp = couch_query_servers:render_reduce_row(QueryServer, 
+            Req, Db, {Key, Value}),
+        #extern_resp_args{
+            stop = StopIter,
+            data = RowBody
+        } = couch_httpd_external:parse_external_response(JsonResp),
+        RowFront2 = case RowFront of
+        nil -> [];
+        _ -> RowFront
+        end,
+        case StopIter of
+        true -> stop;
+        _ ->
+            Chunk = RowFront2 ++ binary_to_list(RowBody),
+            case Chunk of
+                [] -> {ok, Resp};
+                _ -> send_chunk(Resp, Chunk)
+            end
+        end
+    end.
+
+output_reduce_list(#httpd{mochi_req=MReq}=Req, Lang, ListSrc, View, Group, Db, QueryArgs, nil) ->
     #view_query_args{
         limit = Limit,
         direction = Dir,
@@ -187,42 +281,8 @@
     Accept = proplists:get_value('Accept', Hlist),
     CurrentEtag = couch_httpd_view:view_group_etag(Group, {Lang, ListSrc, Accept}),
     couch_httpd:etag_respond(Req, CurrentEtag, fun() ->
-        StartListRespFun = fun(Req2, _Etag, _, _) ->
-            JsonResp = couch_query_servers:render_reduce_head(QueryServer, 
-                Req2, Db),
-            JsonResp2 = apply_etag(JsonResp, CurrentEtag),
-            #extern_resp_args{
-                code = Code,
-                data = BeginBody,
-                ctype = CType,
-                headers = ExtHeaders
-            } = couch_httpd_external:parse_external_response(JsonResp2),
-            JsonHeaders = couch_httpd_external:default_or_content_type(CType, ExtHeaders),
-            {ok, Resp} = start_chunked_response(Req, Code, JsonHeaders),
-            {ok, Resp, binary_to_list(BeginBody)}
-        end,
-    
-        SendListRowFun = fun(Resp, {Key, Value}, RowFront) ->
-            JsonResp = couch_query_servers:render_reduce_row(QueryServer, 
-                Req, Db, {Key, Value}),
-            #extern_resp_args{
-                stop = StopIter,
-                data = RowBody
-            } = couch_httpd_external:parse_external_response(JsonResp),
-            RowFront2 = case RowFront of
-            nil -> [];
-            _ -> RowFront
-            end,
-            case StopIter of
-            true -> stop;
-            _ ->
-                Chunk = RowFront2 ++ binary_to_list(RowBody),
-                case Chunk of
-                    [] -> {ok, Resp};
-                    _ -> send_chunk(Resp, Chunk)
-                end
-            end
-        end,
+        StartListRespFun = make_reduce_start_resp_fun(QueryServer, Req, Db, CurrentEtag),
+        SendListRowFun = make_reduce_send_row_fun(QueryServer, Req, Db),
     
         {ok, GroupRowsFun, RespFun} = couch_httpd_view:make_reduce_fold_funs(Req, 
             GroupLevel, QueryArgs, CurrentEtag, 
@@ -235,6 +295,42 @@
             {EndKey, EndDocId}, GroupRowsFun, RespFun,
             FoldAccInit),
         finish_list(Req, Db, QueryServer, CurrentEtag, FoldResult, StartListRespFun, null)
+    end);
+
+output_reduce_list(#httpd{mochi_req=MReq}=Req, Lang, ListSrc, View, Group, Db, QueryArgs, Keys) ->
+    #view_query_args{
+        limit = Limit,
+        direction = Dir,
+        skip = SkipCount,
+        start_docid = StartDocId,
+        end_docid = EndDocId,
+        group_level = GroupLevel
+    } = QueryArgs,
+    % get the os process here
+    % pass it into the view fold with closures
+    {ok, QueryServer} = couch_query_servers:start_view_list(Lang, ListSrc),
+    Headers = MReq:get(headers),
+    Hlist = mochiweb_headers:to_list(Headers),
+    Accept = proplists:get_value('Accept', Hlist),
+    CurrentEtag = couch_httpd_view:view_group_etag(Group, {Lang, ListSrc, Accept, Keys}),
+
+    couch_httpd:etag_respond(Req, CurrentEtag, fun() ->
+        StartListRespFun = make_reduce_start_resp_fun(QueryServer, Req, Db, CurrentEtag),
+        SendListRowFun = make_reduce_send_row_fun(QueryServer, Req, Db),
+    
+        {ok, GroupRowsFun, RespFun} = couch_httpd_view:make_reduce_fold_funs(Req,
+            GroupLevel, QueryArgs, CurrentEtag, 
+            #reduce_fold_helper_funs{
+                start_response = StartListRespFun,
+                send_row = SendListRowFun
+            }),
+        FoldAccInit = {Limit, SkipCount, undefined, []},
+        FoldResult = lists:foldl(
+            fun(Key, {ok, FoldAcc}) ->
+                couch_view:fold_reduce(View, Dir, {Key, StartDocId},
+                    {Key, EndDocId}, GroupRowsFun, RespFun, FoldAcc)
+            end, {ok, FoldAccInit}, Keys),
+        finish_list(Req, Db, QueryServer, CurrentEtag, FoldResult, StartListRespFun, null)
     end).
 
 finish_list(Req, Db, QueryServer, Etag, FoldResult, StartListRespFun, TotalRows) ->

Modified: couchdb/branches/rep_security/src/couchdb/couch_httpd_view.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/rep_security/src/couchdb/couch_httpd_view.erl?rev=753413&r1=753412&r2=753413&view=diff
==============================================================================
--- couchdb/branches/rep_security/src/couchdb/couch_httpd_view.erl (original)
+++ couchdb/branches/rep_security/src/couchdb/couch_httpd_view.erl Fri Mar 13 21:12:44 2009
@@ -49,13 +49,15 @@
     couch_stats_collector:increment({httpd, view_reads}),
     Result.
 
-handle_view_req(#httpd{method='GET',path_parts=[_,_, Id, ViewName]}=Req, Db) ->
-    design_doc_view(Req, Db, Id, ViewName, nil);
+handle_view_req(#httpd{method='GET',
+        path_parts=[_Db, _Design, DName, _View, ViewName]}=Req, Db) ->
+    design_doc_view(Req, Db, DName, ViewName, nil);
 
-handle_view_req(#httpd{method='POST',path_parts=[_,_, Id, ViewName]}=Req, Db) ->
+handle_view_req(#httpd{method='POST',
+        path_parts=[_Db, _Design, DName, _View, ViewName]}=Req, Db) ->
     {Props} = couch_httpd:json_body(Req),
     Keys = proplists:get_value(<<"keys">>, Props, nil),
-    design_doc_view(Req, Db, Id, ViewName, Keys);
+    design_doc_view(Req, Db, DName, ViewName, Keys);
 
 handle_view_req(Req, _Db) ->
     send_method_not_allowed(Req, "GET,POST,HEAD").

Modified: couchdb/branches/rep_security/src/couchdb/couch_os_process.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/rep_security/src/couchdb/couch_os_process.erl?rev=753413&r1=753412&r2=753413&view=diff
==============================================================================
--- couchdb/branches/rep_security/src/couchdb/couch_os_process.erl (original)
+++ couchdb/branches/rep_security/src/couchdb/couch_os_process.erl Fri Mar 13 21:12:44 2009
@@ -51,7 +51,7 @@
     gen_server:call(Pid, read).
 
 prompt(Pid, Data) ->
-    gen_server:call(Pid, {prompt, Data}).
+    gen_server:call(Pid, {prompt, Data}, infinity).
 
 async(Pid, Data, CallBack) ->
     gen_server:cast(Pid, {async, Data, CallBack}).
@@ -99,12 +99,14 @@
 
 % gen_server API
 init([Command, Options, PortOptions]) ->
+    BaseTimeOut = list_to_integer(couch_config:get(
+        "couchdb", "os_process_timeout", "5000")),
     BaseProc = #os_proc{
         command=Command,
         port=open_port({spawn, Command}, PortOptions),
         writer=fun writejson/2,
         reader=fun readjson/1,
-        timeout=5000
+        timeout=BaseTimeOut
     },
     OsProc =
     lists:foldl(fun(Opt, Proc) ->