root / framework / trunk / corefiles / Application.cfc

Revision 709, 17.8 kB (checked in by scorfield, 10 months ago)

Fixes #330 by adding guards to the use of form/URL scope.

Line 
1<cfcomponent output="false">
2        <cfprocessingdirective suppresswhitespace="true">
3<!---
4Copyright 2006-2007 TeraTech, Inc. http://teratech.com/
5
6Licensed under the Apache License, Version 2.0 (the "License");
7you may not use this file except in compliance with the License.
8You may obtain a copy of the License at
9
10http://www.apache.org/licenses/LICENSE-2.0
11
12Unless required by applicable law or agreed to in writing, software
13distributed under the License is distributed on an "AS IS" BASIS,
14WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15See the License for the specific language governing permissions and
16limitations under the License.
17--->
18
19        <!--- code that must execute at the very start of every single request --->
20        <!--- FB5: allow "" default - FB41 required this variable: --->
21        <cfparam name="variables.FUSEBOX_APPLICATION_PATH" default="" />
22        <!--- FB5: application key - FB41 always uses 'fusebox': --->
23        <cfparam name="variables.FUSEBOX_APPLICATION_KEY" default="fusebox" />
24        <!--- FB51: allow application to be included from other directories: --->
25        <cfparam name="variables.FUSEBOX_CALLER_PATH" default="#replace(getDirectoryFromPath(getBaseTemplatePath()),"\","/","all")#" />
26        <!--- FB55: easy way to override fusebox.xml parameters programmatically: --->
27        <cfparam name="variables.FUSEBOX_PARAMETERS" default="#structNew()#" />
28       
29        <cfparam name="variables.attributes" default="#structNew()#" />
30        <cfif isDefined("URL")>
31                <cfset structAppend(attributes,URL,true) />
32        </cfif>
33        <cfif isDefined("form")>
34                <cfset structAppend(attributes,form,true) />
35        </cfif>
36       
37        <!--- FB5: uses request.__fusebox for internal tracking of compiler / runtime operations: --->
38        <cfset request.__fusebox = structNew() />
39       
40        <!--- FB55: bleeding variables scope back and forth between fusebox5.cfm and this CFC for backward compatibility --->
41        <cfset variables.exposed = structNew() />
42       
43        <!--- FB55: scaffolder integration --->
44        <cfif structKeyExists(attributes,"scaffolding.go")>
45                <!--- if we're not already executing the scaffolder, branch to it --->
46                <cfif findNoCase("/scaffolder/",CGI.SCRIPT_NAME) eq 0>
47                        <cftry>
48                                <cfinclude template="/scaffolder/manager.cfm" />
49                                <cfcatch type="missinginclude">
50                                        <cfif structKeyExists(attributes,"scaffolding.debug")>
51                                                <cfrethrow />
52                                        </cfif>
53                                        <cfthrow type="fusebox.noScaffolder" message="Scaffolder not found" detail="You requested the scaffolder but /scaffolder/index.cfm does not exist." />
54                                </cfcatch>
55                        </cftry>
56                </cfif>
57        </cfif>
58       
59        <cffunction name="bleed" returntype="any" access="public" output="false">
60                <cfargument name="outerVariables" type="any" required="true" />
61               
62                <cfset variables.exposed = arguments.outerVariables />
63                <!--- expose known variables: --->
64                <cfset variables.exposed.attributes = variables.attributes />
65               
66                <cfreturn this />
67               
68        </cffunction>
69
70        <cffunction name="onApplicationStart" output="false">
71
72                <!--- FB5: myFusebox is an object but has FB41-compatible public properties --->
73                <cfset variables.myFusebox = createObject("component","myFusebox").init(variables.FUSEBOX_APPLICATION_KEY,variables.attributes,variables) />
74                <!--- expose known variables: --->
75                <cfset variables.exposed.myFusebox = variables.myFusebox />
76
77                <!--- FB55: guarantee XFA struct exists --->
78                <cfparam name="variables.xfa" default="#structNew()#" />
79                <!--- FB51: ticket 164: add OO synonym for attributes scope --->
80                <cfparam name="variables.event" default="#createObject('component','fuseboxEvent').init(attributes,xfa,myFusebox)#" />
81                <!--- expose known variables: --->
82                <cfset variables.exposed.xfa = variables.xfa />
83                <cfset variables.exposed.event = variables.event />
84               
85                <cfset loadFusebox() />
86
87        </cffunction>
88       
89        <cffunction name="onSessionStart" output="false">
90        </cffunction>
91       
92        <cffunction name="onRequestStart" output="false">
93                <cfargument name="targetPage" type="string" required="true" />
94               
95                <cfset var doCompile = true />
96               
97                <!--- ensure CFC / Web Service / Flex Remoting calls are not intercepted --->
98                <cfif right(arguments.targetPage,4) is ".cfc">
99                        <cfset doCompile = false />
100                        <cfset structDelete(variables,"onRequest") />
101                        <cfset structDelete(this,"onRequest") />
102                </cfif>
103               
104                <!--- onApplicationStart() may create this (on first request) --->
105                <cfif not structKeyExists(variables,"myFusebox")>
106                        <!--- FB5: myFusebox is an object but has FB41-compatible public properties --->
107                        <cfset variables.myFusebox = createObject("component","myFusebox").init(variables.FUSEBOX_APPLICATION_KEY,variables.attributes,variables) />
108                        <!--- expose known variables: --->
109                        <cfset variables.exposed.myFusebox = variables.myFusebox />
110                </cfif>
111
112                <!--- FB55: guarantee XFA struct exists --->
113                <cfparam name="variables.xfa" default="#structNew()#" />
114                <!--- FB51: ticket 164: add OO synonym for attributes scope --->
115                <cfparam name="variables.event" default="#createObject('component','fuseboxEvent').init(variables.attributes,variables.xfa,variables.myFusebox)#" />
116                <!--- expose known variables: --->
117                <cfset variables.exposed.xfa = variables.xfa />
118                <cfset variables.exposed.event = variables.event />
119               
120                <cfif variables.myFusebox.parameters.load>
121                        <cflock name="#application.ApplicationName#_fusebox_#variables.FUSEBOX_APPLICATION_KEY#" type="exclusive" timeout="300">
122                                <cfif variables.myFusebox.parameters.load>
123                                        <cfset loadFusebox() />
124                                <cfelse>
125                                        <!--- _fba should *not* be exposed --->
126                                        <cfset _fba = application[variables.FUSEBOX_APPLICATION_KEY] />
127                                        <!--- fix attributes precedence --->
128                                        <cfif _fba.precedenceFormOrURL is "URL" and isDefined("URL")>
129                                                <cfset structAppend(variables.attributes,URL,true) />
130                                        </cfif>
131                                        <!--- set the default fuseaction if necessary --->
132                                        <cfif not structKeyExists(variables.attributes,_fba.fuseactionVariable) or trim(variables.attributes[_fba.fuseactionVariable]) is "">
133                                                <cfset variables.attributes[_fba.fuseactionVariable] = _fba.defaultFuseaction />
134                                        </cfif>
135                                        <cfset variables.attributes[_fba.fuseactionVariable] = trim(variables.attributes[_fba.fuseactionVariable]) />
136                                        <cfset variables.attributes.fuseaction = variables.attributes[_fba.fuseactionVariable] />
137                                </cfif>
138                        </cflock>
139                <cfelse>
140                        <cfset _fba = application[variables.FUSEBOX_APPLICATION_KEY] />
141                        <!--- fix attributes precedence --->
142                        <cfif _fba.precedenceFormOrURL is "URL">
143                                <cfset structAppend(variables.attributes,URL,true) />
144                        </cfif>
145                        <!--- set the default fuseaction if necessary --->
146                        <cfif not structKeyExists(variables.attributes,_fba.fuseactionVariable) or trim(variables.attributes[_fba.fuseactionVariable]) is "">
147                                <cfset variables.attributes[_fba.fuseactionVariable] = _fba.defaultFuseaction />
148                        </cfif>
149                        <cfset variables.attributes[_fba.fuseactionVariable] = trim(variables.attributes[_fba.fuseactionVariable]) />
150                        <cfset variables.attributes.fuseaction = variables.attributes[_fba.fuseactionVariable] />
151                </cfif>
152
153                <!---
154                        Fusebox 4.1 did not set attributes.fuseaction or default the fuseaction variable until
155                        *after* fusebox.init.cfm had run. This made it hard for fusebox.init.cfm to do URL
156                        rewriting. For Fusebox 5, we default the fuseaction variable and set attributes.fuseaction
157                        before fusebox.init.cfm so it can rely on attributes.fuseaction and rewrite that. However,
158                        in order to maintain backward compatibility, we need to allow fusebox.init.cfm to set
159                        attributes[_fba.fuseactionVariable] and still have that reflected in attributes.fuseaction
160                        and for that to actually be the request that gets processed.
161                --->
162                <cfif _fba.debug>
163                        <cfset variables.myFusebox.trace("Fusebox","Including fusebox.init.cfm") />
164                </cfif>
165                <cftry>
166                        <!--- _fba_ttr_fav and _ba_attr_fa should *not* be exposed --->
167                        <cfset _fba_attr_fav = variables.attributes[_fba.fuseactionVariable] />
168                        <cfset _fba_attr_fa = variables.attributes.fuseaction />
169                        <cfinclude template="#_fba.getCoreToAppRootPath()#fusebox.init.cfm" />
170                        <cfif variables.attributes.fuseaction is not _fba_attr_fa>
171                                <cfif variables.attributes.fuseaction is not variables.attributes[_fba.fuseactionVariable]>
172                                        <cfif variables.attributes[_fba.fuseactionVariable] is not _fba_attr_fav>
173                                                <!--- inconsistent modification of both variables?!? --->
174                                                <cfthrow type="fusebox.inconsistentFuseaction"
175                                                                message="Inconsistent fuseaction variables"
176                                                                detail="Both attributes.fuseaction and attributes[{fusebox}.fuseactionVariable] changed in fusebox.init.cfm so Fusebox doesn't know what to do with the values!" />
177                                        <cfelse>
178                                                <!--- ok, only attributes.fuseaction changed --->
179                                                <cfset variables.attributes[_fba.fuseactionVariable] = variables.attributes.fuseaction />
180                                        </cfif>
181                                <cfelse>
182                                        <!--- ok, they were both changed and they match --->
183                                </cfif>
184                        <cfelse>
185                                <!--- attributes.fuseaction did not change --->
186                                <cfif variables.attributes[_fba.fuseactionVariable] is not _fba_attr_fav>
187                                        <!--- make attributes.fuseaction match the other changed variable --->
188                                        <cfset variables.attributes.fuseaction = variables.attributes[_fba.fuseactionVariable] />
189                                <cfelse>
190                                        <!--- ok, neither variable changed --->
191                                </cfif>
192                        </cfif>
193                <cfcatch type="missinginclude" />
194                </cftry>
195                <cfif doCompile>
196                        <!---
197                                must special case development-circuit-load mode since it causes circuits to reload during
198                                the compile (post-load) phase and therefore must be exclusive
199                        --->
200                        <cfif _fba.debug>
201                                <cfset variables.myFusebox.trace("Fusebox","Compiling requested fuseaction '#variables.attributes.fuseaction#'") />
202                        </cfif>
203                        <!--- _parsedFileData should *not* be exposed --->
204                        <cfif _fba.mode is "development-circuit-load">
205                                <cflock name="#application.ApplicationName#_fusebox_#variables.FUSEBOX_APPLICATION_KEY#" type="exclusive" timeout="300">
206                                        <cfset _parsedFileData = _fba.compileRequest(attributes.fuseaction,myFusebox) />
207                                </cflock>
208                        <cfelse>
209                                <cflock name="#application.ApplicationName#_fusebox_#variables.FUSEBOX_APPLICATION_KEY#" type="readonly" timeout="300">
210                                        <cfset _parsedFileData = _fba.compileRequest(attributes.fuseaction,myFusebox) />
211                                </cflock>
212                        </cfif>
213                </cfif>
214               
215        </cffunction>
216       
217        <!--- excuse the formatting here - it is done to completely suppress whitespace --->
218        <cffunction name="onRequest"><cfargument
219                                name="targetPage" type="string" required="true" /><cfsetting
220                                                        enablecfoutputonly="true">
221               
222                <cfif variables.myFusebox.parameters.execute>
223                        <cfif _fba.debug>
224                                <cfset myFusebox.trace("Fusebox","Including parsed file for '#variables.attributes.fuseaction#'") />
225                        </cfif>
226                        <cftry>
227                                <!---
228                                        readonly lock protects against including the parsed file while
229                                        another threading is writing it...
230                                --->
231                                <cflock name="#_parsedFileData.lockName#" type="readonly" timeout="30">
232                                        <cfinclude template="#_parsedFileData.parsedFile#" />
233                                </cflock>
234                        <cfcatch type="missinginclude">
235                                <cfif right(cfcatch.missingFileName, len(_parsedFileData.parsedName)) is _parsedFileData.parsedName>
236                                        <cfthrow type="fusebox.missingParsedFile"
237                                                        message="Parsed File or Directory not found."
238                                                        detail="Attempting to execute the parsed file '#_parsedFileData.parsedName#' threw an error. This can occur if the parsed file does not exist in the parsed directory or if the parsed directory itself is missing." />
239                                <cfelse>
240                                        <cfrethrow />
241                                </cfif>
242                        </cfcatch>
243                        </cftry>
244                </cfif>
245               
246                <cfsetting enablecfoutputonly="false">
247        </cffunction>
248       
249        <cffunction name="onRequestEnd" output="true">
250                <cfargument name="targetPage" type="string" required="true" />
251
252                <cfif structKeyExists(variables,"myFusebox")>
253                        <cfset variables.myFusebox.trace("Fusebox","Request completed") />
254                </cfif>
255                <cfif isDefined("_fba.debug") and _fba.debug and structKeyExists(variables,"myFusebox") and right(arguments.targetPage,4) is not ".cfc">
256                        <cfoutput>#variables.myFusebox.renderTrace()#</cfoutput>
257                </cfif>
258
259        </cffunction>
260       
261        <cffunction name="onSessionEnd" output="false">
262        </cffunction>
263       
264        <cffunction name="onApplicationEnd" output="false">
265        </cffunction>
266       
267        <cffunction name="onError">
268                <cfargument name="exception" />
269               
270                <cfset var stack = 0 />
271                <cfset var prefix = "Raised at " />
272               
273                <!--- top-level exception is always event name / expression for Application.cfc (but not fusebox5.cfm) --->
274                <cfset var caughtException = arguments.exception />
275               
276                <cfif structKeyExists(caughtException,"rootcause")>
277                        <cfset caughtException = caughtException.rootcause />
278                </cfif>
279               
280                <cfif listFirst(caughtException.type,".") is "fusebox">
281                        <cfif isDefined("_fba.debug") and _fba.debug and structKeyExists(variables,"myFusebox")>
282                                <cfset variables.myFusebox.trace("Fusebox","Caught Fusebox exception '#caughtException.type#'") />
283                                <cfif structKeyExists(caughtException,"tagcontext")>
284                                        <cfloop index="stack" from="1" to="#arrayLen(caughtException.tagContext)#">
285                                                <cfset variables.myFusebox.trace("Fusebox",prefix &
286                                                                caughtException.tagContext[stack].template & ":" &
287                                                                caughtException.tagContext[stack].line) />
288                                                <cfset prefix = "Called from " />
289                                        </cfloop>
290                                </cfif>
291                        </cfif>
292                        <cfif not isDefined("_fba.errortemplatesPath") or (
293                                        structKeyExists(variables,"attributes") and structKeyExists(variables,"myFusebox") and
294                                        not _fba.handleFuseboxException(caughtException,variables.attributes,variables.myFusebox,variables.FUSEBOX_APPLICATION_KEY)
295                                        )>
296                                <cfif isDefined("_fba.debug") and _fba.debug and structKeyExists(variables,"myFusebox")>
297                                        <cfoutput>#variables.myFusebox.renderTrace()#</cfoutput>
298                                </cfif>
299                                <cfthrow object="#caughtException#" />
300                        </cfif>
301                <cfelse>
302                        <cfif isDefined("_fba.debug") and _fba.debug and structKeyExists(variables,"myFusebox")>
303                                <cfset variables.myFusebox.trace("Fusebox","Request failed with exception '#caughtException.type#' (#caughtException.message#)") />
304                                <cfif structKeyExists(caughtException,"tagcontext")>
305                                        <cfloop index="stack" from="1" to="#arrayLen(caughtException.tagContext)#">
306                                                <cfset variables.myFusebox.trace("Fusebox",prefix &
307                                                                caughtException.tagContext[stack].template & ":" &
308                                                                caughtException.tagContext[stack].line) />
309                                                <cfset prefix = "Called from " />
310                                        </cfloop>
311                                </cfif>
312                                <cfoutput>#variables.myFusebox.renderTrace()#</cfoutput>
313                        </cfif>
314                        <cfthrow object="#caughtException#" />
315                </cfif>
316               
317                <!--- if we hit an error before starting the request, prevent the request from running --->
318                <cfset myFusebox.parameters.execute = false />
319               
320        </cffunction>
321       
322        <cffunction name="override" returntype="void" access="public" output="false">
323                <cfargument name="name" type="string" required="true" />
324                <cfargument name="value" type="any" required="true" />
325                <cfargument name="useThisScope" type="boolean" default="false" />
326               
327                <cfif arguments.useThisScope>
328                        <cfset this[arguments.name] = arguments.value />
329                <cfelse>
330                        <cfset variables[arguments.name] = arguments.value />
331                </cfif>
332               
333        </cffunction>
334       
335        <cffunction name="onFuseboxApplicationStart">
336        </cffunction>
337       
338        <cffunction name="loadFusebox" access="private" output="false">
339                <!--- ticket 232: extend request timeout value on framework load --->
340                <cfsetting requesttimeout="600" />
341                <cfif not structKeyExists(application,variables.FUSEBOX_APPLICATION_KEY) or variables.myFusebox.parameters.userProvidedLoadParameter>
342                        <!--- can't be conditional: we don't know the state of the debug flag yet --->
343                        <cfset variables.myFusebox.trace("Fusebox","Creating Fusebox application object") />
344                        <cfset _fba = createObject("component","fuseboxApplication") />
345                        <cfset application[variables.FUSEBOX_APPLICATION_KEY] = _fba.init(variables.FUSEBOX_APPLICATION_KEY,variables.FUSEBOX_APPLICATION_PATH,variables.myFusebox,variables.FUSEBOX_CALLER_PATH,variables.FUSEBOX_PARAMETERS) />
346                <cfelse>
347                        <!--- can't be conditional: we don't know the state of the debug flag yet --->
348                        <cfset variables.myFusebox.trace("Fusebox","Reloading Fusebox application object") />
349                        <cfset _fba = application[variables.FUSEBOX_APPLICATION_KEY] />
350                        <!--- it exists and the load is implicit, not explicit (via user) so just reload XML --->
351                        <cfset _fba.reload(variables.FUSEBOX_APPLICATION_KEY,variables.FUSEBOX_APPLICATION_PATH,variables.myFusebox,variables.FUSEBOX_PARAMETERS) />
352                </cfif>
353                <!--- fix attributes precedence --->
354                <cfif _fba.precedenceFormOrURL is "URL">
355                        <cfset structAppend(variables.attributes,URL,true) />
356                </cfif>
357                <!--- set the default fuseaction if necessary --->
358                <cfif not structKeyExists(variables.attributes,_fba.fuseactionVariable) or variables.attributes[_fba.fuseactionVariable] is "">
359                        <cfset variables.attributes[_fba.fuseactionVariable] = _fba.defaultFuseaction />
360                </cfif>
361                <!--- set this up for fusebox.appinit.cfm --->
362                <cfset variables.attributes.fuseaction = variables.attributes[_fba.fuseactionVariable] />
363                <!--- flag this as the first request for the application --->
364                <cfset variables.myFusebox.applicationStart = true />
365                <!--- force parse after reload for consistency in development modes --->
366                <cfif _fba.mode is not "production" or variables.myFusebox.parameters.userProvidedLoadParameter>
367                        <cfset variables.myFusebox.parameters.parse = true />
368                </cfif>
369                <!--- need all of the above set before we attempt any compiles! --->
370                <cfif variables.myFusebox.parameters.parseall>
371                        <cfset _fba.compileAll(variables.myFusebox) />
372                </cfif>
373                <!--- FB55: template method to allow no-XML application initialization --->
374                <cfif _fba.debug>
375                        <cfset variables.myFusebox.trace("Fusebox","Executing onFuseboxApplicationStart()") />
376                </cfif>
377                <cfset onFuseboxApplicationStart() />
378                <!--- FB5: new appinit include file --->
379                <cfif _fba.debug>
380                        <cfset variables.myFusebox.trace("Fusebox","Including fusebox.appinit.cfm") />
381                </cfif>
382                <cftry>
383                        <cfinclude template="#_fba.getCoreToAppRootPath()#fusebox.appinit.cfm" />
384                <cfcatch type="missinginclude" />
385                </cftry>
386                <!--- ticket 269 ensure there is no double reload at CF startup --->
387                <cfset variables.myFusebox.parameters.load = false />
388        </cffunction>
389       
390        </cfprocessingdirective>
391</cfcomponent>
Note: See TracBrowser for help on using the browser.