/** * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS-IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileOverview Dispatching for dynamic pages and static files rendered from disk. */ import("jsutils.eachProperty"); import("stringutils"); jimport("java.lang.System.out.println"); //---------------------------------------------------------------- // Util //---------------------------------------------------------------- function PrefixMatcher(p) { var rs = p.replace(/([\[\]\^\$\\\.\*\+\?\(\)\{\}\|])/g, "\\$1"); var r = new RegExp('^' + rs + '(.*)$'); return function(path) { return r.exec(path); } } // Like PrefixMatcher, but makes trailing '/' optional, as in /ep/admin or /ep/admin/. // If trailing '/' is omitted, will redirect to same path with trailing /. function DirMatcher(p) { if (p.substr(-1) == '/') { p = p.substr(0, p.length-1); } var prefixMatcher = PrefixMatcher(p+'/'); return function(path) { if (path == p) { response.redirect(p+'/'); } return prefixMatcher(path); } } function _pathMatches(p, loc) { // returns a regex-result kind of array with length >= 1, or null if (typeof(loc) == 'string') { return (p == loc) ? [loc] : null; } if (typeof(loc) == 'function') { return (loc(p) || null); } if (loc.exec) { // regexp var r = loc.exec(p); return r || null; } throw new Error('Uknown type of location: '+loc); } //---------------------------------------------------------------- // Dispatcher //---------------------------------------------------------------- var Dispatcher = function() { this._routes = []; // Array([location, (local file path or function)]) }; Dispatcher.prototype.addLocations = function(l) { var that = this; l.forEach(function(x) { that._routes.push(x); }); }; Dispatcher.prototype.dispatch = function() { var p = request.path; var served = false; for (var i = 0; (i < this._routes.length) && (served == false); i++) { var loc = this._routes[i][0]; var dst = this._routes[i][1]; var match = _pathMatches(p, loc); if (match) { if (typeof(dst) != 'function') { throw new Error('dispatch only dispatches to functions, and this is not a function: '+typeof(dst)); } // call dst(group1, group2, group3, ...) served = dst.apply(this, Array.prototype.slice.call(match, 1)); } }; return served; }; //---------------------------------------------------------------- // fdisp //---------------------------------------------------------------- function forward(module) { return function(name) { if (name === "") { name = "main"; } if (name) { name = name.replace(/\-/g, '_'); } var onreq = module['onRequest']; var f = module['render_'+name]; var fg = module['render_'+name+'_get']; var fp = module['render_'+name+'_post']; var served = false; if (onreq) { served = onreq(name); } if (served) { return true; } var method = request.method; if (method == "HEAD") { method = "GET"; } if (f) { f(); served = true; } else if (method == "GET" && fg) { fg(); served = true; } else if (method == "POST" && fp) { fp(); served = true; } return served; }; }