assert api.cgi
scope { /* Set up some extra CGI environment... */
const CGI = api.cgi
const R = CGI.request;
const uri = R.ENV.REQUEST_URI
if(uri){
/* Some hackery/normalizing of the root path for creating links... */
const indexPageName = 'index.cgi' // kludge!
const lastChar = uri.charAt(uri.length()-1)
if(uri.indexOf('.cgi') < 0){
if('/' === lastChar ){
CGI.cgiRoot = uri + indexPageName + '/'
}else{
CGI.cgiRoot = uri // ???
}
}else{
if('/' !== lastChar ){
CGI.cgiRoot = uri.split('.cgi').0+'.cgi/'
}else{
CGI.cgiRoot = uri
}
}
}
const serverName = R.ENV.SERVER_NAME
CGI.isLocalServer = ((!serverName) || (0<=serverName.indexOf(".local")))
if(R.ENV.PATH_INFO && CGI.cgiRoot){
CGI.pageLinkRoot = CGI.cgiRoot + R.ENV.PATH_INFO.substr(1/*trim leading slash*/)
}else{
CGI.pageLinkRoot = CGI.cgiRoot
}
}
api.cgi.config = object{
scrubExceptions: !api.cgi.isLocalServer,//true,
onlyDeepestException: true,//false
sessionCookieKey: 'fSession',
cookiePath: api.cgi.cgiRoot
}
api.cgi.out = api.io.output
/**
Removes "potentially security-relevant" properties from the
exception ex, recursively in all 'rethrown' exceptions. If
ex.rethrown is set and api.cgi.config.onlyDeepestException is
true, it returns that value, else return ex.
*/
api.cgi.scrubException = proc(ex){
if(this.config.scrubExceptions){
unset ex.script, ex.callStack, ex.line, ex.column // security-relevant
}
//this.config.onlyDeepestException && return ex
ex.rethrown && argv.callee.call(this, ex.rethrown)
return (this.config.onlyDeepestException && ex.rethrown) ? ex.rethrown : ex
}
/**
Assumes obj is a legal value for the 'J' format specifier for Buffer.appendf()
and outputs that data using some default, unspecified JSON indentation setting.
*/
api.cgi.printJSON = proc(obj){
print("%1$2J".applyFormat(obj))
}
/**
Assumes obj is a legal value for the 'J' format specifier for Buffer.appendf()
and returns that data's JSON string form, unspecified JSON indentation setting.
*/
api.cgi.toJSONString = proc(obj){
return "%1$2J".applyFormat(obj)
}
/**
Returns a variable from the GET, POST, or COOKIES
data, in that order, or default if none of those
sets contain the given key.
*/
api.cgi.getVar = proc(name, default = undefined){
const R = this.request
var rc = default
if(R.GET && R.GET.hasOwnProperty(name)){
rc = R.GET.(name)
//CGI.setCookie('limit', resultLimit)
}else if(R.POST && R.POST.hasOwnProperty(name)){
rc = R.POST.(name)
}else if(R.COOKIES && R.COOKIES.hasOwnProperty(name)){
rc = R.COOKIES.(name)
}
return rc
}
api.cgi.getCookie = proc(name){
const c = this.request.COOKIES
return (c && c.hasOwnProperty(name)) ? c.(name) : undefined
}
/**
Returns an app-specific session object, for storing _small amounts_
of persistent data. The session is submitted as a single JSON-encoded
cookie, so the data should be small.
The session is loaded or initialized the first time this is called,
and each time it is called, the session's 'lifetime' property is
updated.
*/
api.cgi.getSession = proc(){
var s = argv.callee.session
if(!s){
s = this.getCookie(this.config.sessionCookieKey)
s && catch{
const x = s
s = null
s = api.json.parse(x)
}
(s inherits api.Exception) && (s=null)
s || (s = object{
sessionId: 1234,
startTime: time()
})
s.startTime || (s.startTime = time())
s.lifetime = time()-s.startTime
s.visitCount = 1 + (+s.visitCount)
argv.callee.session = s
}
return s
}
/**
Don't use this - it turns out that each sub-path sets its own
cookie, no matter what path we tell it to use.
Encodes api.cgi.getSession() to JSON and sets it as the
cookie named by api.cgi.config.sessionCookieKey.
*/
api.cgi.savePathSession = proc(){
var s = this.getSession()
this.setCookie(this.config.sessionCookieKey, object{
path: '/', // this.config.cookiePath,
value:"%1$J".applyFormat(s)
})
}