diff options
Diffstat (limited to 'share/server/render.js')
-rw-r--r-- | share/server/render.js | 183 |
1 files changed, 136 insertions, 47 deletions
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; - } -}; |