/**
* 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;
};
}