/usr/lib/falcon/web/ajax.fal is in libfalcon-engine1 0.9.6.9-git20120606-2.1+b1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 | /*
FALCON - The Falcon Programming Language
FILE: ajax.fal
Module supporting AJAX hybrid client-server development.
-------------------------------------------------------------------
Author: Giancarlo Niccolai
Begin: Wed, 14 Jul 2010 14:26:45 +0200
-------------------------------------------------------------------
(C) Copyright 2010: the FALCON developers (see list in AUTHORS file)
See LICENSE file for licensing details.
*/
import JSONencode from json as JSONencode
import ZLib from zlib as ZLib
const zip_mode = "deflate"
/*# @main AJAX hybrid server-client support.
@note As this is a web component, this module is to be used under WOPI.
This module simplifies the development of AJAX components
of dynamic web-sites.
It consists of a master class @a Function that helps implementing
server-site web functions participating in AJAX data exchanges.
*/
/*# AJAX function parameter.
@param name Name of the parameter
@optparam mand If true, the parameter is mandatory; if not received from the web, an error will be returned.
@optparam check Fucntion performing consistency checks on the received value.
*/
class Param( name, mand, check )
name = name
mand = mand
check = check
end
/*# Ajax server-side function wrapper.
@param dry Just create a descriptive instance.
*/
class Function(dry)
//# Name of the fucntion -- defaults to the class.
name = nil
//# @ignore
dry = dry
//# Compress the reply
zipReply = false
//# Set the max age for a reply (?)
maxAge = "1728000"
//# Array of allowed origins (nil to allow all)
originFilter = nil
//# Specify an array of application-wise headers that you want to pass through, or nil for none
headerFilter = nil
//# Errors that can be generated by this function
errorMap = nil
//# Array of Parameters object describing the parameters of this entity
parameters = nil
/*# Generats a dictionary that can be sent as an error report.
@param id The error ID
@optparam detail Detail to be added to the error description.
Returns a dictionary containing the following entries:
- error: The @b id passed as parameter.
- edesc: Error descrption, taken from the @a errorMap property, if the @b id
error code is associated to a description. If not, this element is
not inserted in the returned dictionary.
- detail: If the @b detail parameter is specified, this key is added to the
dictionary and the @b detail value is added here.
The following errors are added to all the Ajax subclasses, and are always
available:
- -1 = Uncaught exception
- -2 = Missing mandatory parameters
- -3 = run() method not reimplmented
*/
function error( id, detail )
edict = ["error" => id]
if detail
edict += ["detail" => detail ]
end
if id in self.errorMap
edict += ["edesc" => self.errorMap[id] ]
end
return edict
end
//# @ignore
function setup()
missing = []
// grab the parameters
func = [self.run]
for param in self.parameters
value = Request.getField( param.name, nil )
if value
if param.check
value = param.check( value, self )
end
elif param.mand
missing += param.name
end
// anyhow, form the call
func += value
end
if missing: raise self.error( -2, ",".merge(missing) )
return func
end
/*# Method implementing the functionalities of this AJAX function.
@return A dictionary of key-value objects to be sent as ajax values.
*/
function run()
raise self.error( -3 )
end
/*# Returns a list of names the parameters of this AJAX function.
@return A list of parameter names.
*/
function paramNames()
return map( { v => v.name}, self.parameters )
end
//================================================================
// Ajax specifics
//
function _handleOptions()
h = Request.headers
if "Access-Control-Request-Method" in h
mth = strUpper( h["Access-Control-Request-Method"] )
if mth != "POST" and mth != "GET" and mth != "ORIGIN"
Reply.status = 501
Reply.reason = "Method " + mth + " not allowed"
Reply.commit()
return
end
end
Reply.setHeader( "Access-Control-Allow-Methods", "POST, GET, OPTIONS" )
Reply.setHeader( "Access-Control-Max-Age", self.maxAge )
self._filterOrigin()
if "Access-Control-Request-Headers" in h
if self.headerFilter
chead = ", ".merge(self.headerFilter)
Reply.setHeader( "Access-Control-Allow-Headers", chead )
end
// otherwise, we don't pass through any application header.
end
Reply.setHeader( "Content-Length", "0" )
Reply.setHeader( "Content-Type", "application/json" )
self._checkZip()
Reply.commit()
end
function _handleAJAXReq()
self._filterOrigin()
self._checkZip()
h = Request.headers
for passHeader in self.headerFilter
if passHeader in h
Reply.setHeader( passHeader, h[passHeader] )
end
end
end
function _filterOrigin()
h = Request.headers
if self.originFilter
if "Origin" in h
origin = h["Origin"]
if origin in self.originFilter
Reply.setHeader( "Access-Control-Allow-Origin", origin )
end
end
else
Reply.setHeader( "Access-Control-Allow-Origin","*" )
end
end
function _checkZip()
h = Request.headers
if self.zipReply
// is the remote side agreeing?
if "Accept-Encoding" in h
if zip_mode in map( {v=>v.trim()}, h["Accept-Encoding"].split(",") )
Reply.setHeader( "Content-Encoding", zip_mode )
return
end
end
// nope, remote won't accept
self.zipReply = false
end
end
function _process()
// If the remote asked our options...
if Request.method == "OPTIONS"
// just tell who we are and exit.
self._handleOptions()
return
else
// else, prepare a vaild ajax reply.
self._handleAJAXReq()
end
try
// Read the paramters and check the value
func = self.setup()
// Run the subclass run method.
result = func()
catch DictionaryType in errorDesc
result = errorDesc
catch in error
result = self.error( -1, error.toString() )
end
retval = JSONencode( result )
// should we encode the result?
if self.zipReply
retval = ZLib.compress( retval )
end
// dispatch the data.
Reply.commit()
stdOut().write( retval )
end
//========================================================
// Post creation initialization
//
[init]
function __enter()
// --- sets the name of the function if not already set
self.name = self.className().replace( "%", "")
// --- adds the standard error map
standardErrors = [
-1 => i"Uncaught exception",
-2 => i"Missing mandatory parameters",
-3 => i"run() method not reimplmented"
]
if self.errorMap
self.errorMap += standardErrors
else
self.errorMap = standardErrors
end
if not self.dry
self._process()
end
end
end
end
|