summaryrefslogtreecommitdiff
path: root/share/server
diff options
context:
space:
mode:
Diffstat (limited to 'share/server')
-rw-r--r--share/server/loop.js25
-rw-r--r--share/server/render.js183
-rw-r--r--share/server/util.js5
3 files changed, 151 insertions, 62 deletions
diff --git a/share/server/loop.js b/share/server/loop.js
index db6a9702..188692ba 100644
--- a/share/server/loop.js
+++ b/share/server/loop.js
@@ -21,6 +21,9 @@ try {
sandbox.toJSON = toJSON;
sandbox.respondWith = respondWith;
sandbox.registerType = registerType;
+ sandbox.start = start;
+ sandbox.send = send;
+ sandbox.getRow = getRow;
} catch (e) {}
// Commands are in the form of json arrays:
@@ -31,21 +34,19 @@ try {
var line, cmd, cmdkey;
var dispatch = {
- "reset" : State.reset,
- "add_fun" : State.addFun,
- "map_doc" : Views.mapDoc,
- "reduce" : Views.reduce,
- "rereduce" : Views.rereduce,
- "validate" : Validate.validate,
- "show_doc" : Render.showDoc,
- "list_begin" : Render.listBegin,
- "list_row" : Render.listRow,
- "list_tail" : Render.listTail
+ "reset" : State.reset,
+ "add_fun" : State.addFun,
+ "map_doc" : Views.mapDoc,
+ "reduce" : Views.reduce,
+ "rereduce" : Views.rereduce,
+ "validate" : Validate.validate,
+ "show" : Render.show,
+ "list" : Render.list
};
while (line = eval(readline())) {
- cmd = eval(line)
- line_length = line.length
+ cmd = eval(line);
+ line_length = line.length;
try {
cmdkey = cmd.shift();
if (dispatch[cmdkey]) {
diff --git a/share/server/render.js b/share/server/render.js
index 13ef1322..99541eab 100644
--- a/share/server/render.js
+++ b/share/server/render.js
@@ -12,9 +12,10 @@
// mimeparse.js
// http://code.google.com/p/mimeparse/
+// MIT Licensed http://www.opensource.org/licenses/mit-license.php
// Code with comments: http://mimeparse.googlecode.com/svn/trunk/mimeparse.js
// Tests: http://mimeparse.googlecode.com/svn/trunk/mimeparse-js-test.html
-// Ported from version 0.1.2
+// Ported by Chris Anderson from version 0.1.2
var Mimeparse = (function() {
function strip(string) {
@@ -111,6 +112,8 @@ var Mimeparse = (function() {
return publicMethods;
})();
+var respCT;
+var respTail;
// this function provides a shortcut for managing responses by Accept header
respondWith = function(req, responders) {
var bestKey = null, accept = req.headers["Accept"];
@@ -127,11 +130,16 @@ respondWith = function(req, responders) {
bestKey = req.query.format;
}
var rFunc = responders[bestKey || responders.fallback || "html"];
- if (rFunc) {
- var resp = maybeWrapResponse(rFunc());
- resp["headers"] = resp["headers"] || {};
- resp["headers"]["Content-Type"] = bestMime;
- respond(resp);
+ if (rFunc) {
+ if (isShow) {
+ var resp = maybeWrapResponse(rFunc());
+ resp["headers"] = resp["headers"] || {};
+ resp["headers"]["Content-Type"] = bestMime;
+ respond(["resp", resp]);
+ } else {
+ respCT = bestMime;
+ respTail = rFunc();
+ }
} else {
throw({code:406, body:"Not Acceptable: "+accept});
}
@@ -162,8 +170,6 @@ registerType("text", "text/plain", "txt");
registerType("html", "text/html");
registerType("xhtml", "application/xhtml+xml", "xhtml");
registerType("xml", "application/xml", "text/xml", "application/x-xml");
-// http://www.ietf.org/rfc/rfc4627.txt
-registerType("json", "application/json", "text/x-json");
registerType("js", "text/javascript", "application/javascript", "application/x-javascript");
registerType("css", "text/css");
registerType("ics", "text/calendar");
@@ -171,57 +177,148 @@ registerType("csv", "text/csv");
registerType("rss", "application/rss+xml");
registerType("atom", "application/atom+xml");
registerType("yaml", "application/x-yaml", "text/yaml");
+
// just like Rails
registerType("multipart_form", "multipart/form-data");
registerType("url_encoded_form", "application/x-www-form-urlencoded");
+// http://www.ietf.org/rfc/rfc4627.txt
+registerType("json", "application/json", "text/x-json");
+
+
+
+// Start chunks
+var startResp = {};
+function start(resp) {
+ startResp = resp || {};
+};
+
+function sendStart(label) {
+ startResp = startResp || {};
+ startResp["headers"] = startResp["headers"] || {};
+ startResp["headers"]["Content-Type"] = startResp["headers"]["Content-Type"] || respCT;
+
+ respond(["start", chunks, startResp]);
+ chunks = [];
+ startResp = {};
+}
+// Send chunk
+var chunks = [];
+function send(chunk) {
+ chunks.push(chunk.toString());
+};
+
+function blowChunks(label) {
+ respond([label||"chunks", chunks]);
+ chunks = [];
+};
+
+var gotRow = false, lastRow = false;
+function getRow() {
+ if (lastRow) return null;
+ if (!gotRow) {
+ gotRow = true;
+ sendStart();
+ } else {
+ blowChunks()
+ }
+ var line = readline();
+ var json = eval(line);
+ if (json[0] == "list_end") {
+ lastRow = true
+ return null;
+ }
+ if (json[0] != "list_row") {
+ respond({
+ error: "query_server_error",
+ reason: "not a row '" + json[0] + "'"});
+ quit();
+ }
+ return json[1];
+};
+
+////
+//// Render dispatcher
+////
+////
+////
+////
+var isShow = false;
var Render = (function() {
var row_info;
+
return {
- showDoc : function(funSrc, doc, req) {
+ show : function(funSrc, doc, req) {
+ isShow = true;
var formFun = compileFunction(funSrc);
- runRenderFunction(formFun, [doc, req], funSrc);
- },
- listBegin : function(head, req) {
- row_info = { first_key: null, row_number: 0, prev_key: null };
- runRenderFunction(funs[0], [head, null, req, null], funsrc[0]);
- },
- listRow : function(row, req) {
- if (row_info.first_key == null) {
- row_info.first_key = row.key;
- }
- runRenderFunction(funs[0], [null, row, req, row_info], funsrc[0], true);
- row_info.prev_key = row.key;
- row_info.row_number++;
+ runShowRenderFunction(formFun, [doc, req], funSrc, true);
},
- listTail : function(req) {
- runRenderFunction(funs[0], [null, null, req, row_info], funsrc[0]);
+ list : function(head, req) {
+ isShow = false;
+ runListRenderFunction(funs[0], [head, req], funsrc[0], false);
}
}
})();
-function runRenderFunction(renderFun, args, funSrc, htmlErrors) {
- responseSent = false;
+function maybeWrapResponse(resp) {
+ var type = typeof resp;
+ if ((type == "string") || (type == "xml")) {
+ return {body:resp};
+ } else {
+ return resp;
+ }
+};
+
+function runShowRenderFunction(renderFun, args, funSrc, htmlErrors) {
try {
var resp = renderFun.apply(null, args);
- if (!responseSent) {
- if (resp) {
- respond(maybeWrapResponse(resp));
- } else {
- respond({error:"render_error",reason:"undefined response from render function"});
- }
+ if (resp) {
+ respond(["resp", maybeWrapResponse(resp)]);
+ } else {
+ renderError("undefined response from render function");
}
} catch(e) {
- var logMessage = "function raised error: "+e.toString();
- log(logMessage);
- // log("stacktrace: "+e.stack);
- var errorMessage = htmlErrors ? htmlRenderError(e, funSrc) : logMessage;
- respond({
- error:"render_error",
- reason:errorMessage});
+ respondError(e, funSrc, htmlErrors);
}
};
+function runListRenderFunction(renderFun, args, funSrc, htmlErrors) {
+ try {
+ gotRow = false;
+ lastRow = false;
+ respTail = "";
+ if (renderFun.arity > 2) {
+ throw("the list API has changed for CouchDB 0.10, please upgrade your code");
+ }
+ var resp = renderFun.apply(null, args);
+ if (!gotRow) {
+ getRow();
+ }
+ if (typeof resp != "undefined") {
+ chunks.push(resp);
+ } else if (respTail) {
+ chunks.push(respTail);
+ }
+ blowChunks("end");
+ } catch(e) {
+ respondError(e, funSrc, htmlErrors);
+ }
+};
+
+function renderError(m) {
+ respond({error : "render_error", reason : m});
+}
+
+
+function respondError(e, funSrc, htmlErrors) {
+ var logMessage = "function raised error: "+e.toString();
+ log(logMessage);
+ log("stacktrace: "+e.stack);
+ var errorMessage = htmlErrors ? htmlRenderError(e, funSrc) : logMessage;
+ respond({
+ error:"render_error",
+ reason:errorMessage});
+}
function escapeHTML(string) {
return string.replace(/&/g, "&")
@@ -241,11 +338,3 @@ function htmlRenderError(e, funSrc) {
return {body:msg};
};
-function maybeWrapResponse(resp) {
- var type = typeof resp;
- if ((type == "string") || (type == "xml")) {
- return {body:resp};
- } else {
- return resp;
- }
-};
diff --git a/share/server/util.js b/share/server/util.js
index 7faf2f0b..13b8a779 100644
--- a/share/server/util.js
+++ b/share/server/util.js
@@ -91,10 +91,8 @@ function recursivelySeal(obj) {
}
}
-var responseSent;
// prints the object as JSON, and rescues and logs any toJSON() related errors
function respond(obj) {
- responseSent = true;
try {
print(toJSON(obj));
} catch(e) {
@@ -103,10 +101,11 @@ function respond(obj) {
};
log = function(message) {
+ // return;
if (typeof message == "undefined") {
message = "Error: attempting to log message of 'undefined'.";
} else if (typeof message != "string") {
message = toJSON(message);
}
- print(toJSON({log: message}));
+ respond(["log", message]);
};