Fix for ColdFusion 8 Broken Exception HTTP Response

August 1, 2007 on 3:44 am | In Java, Adobe, ColdFusion | No Comments

Here’s a quick and dirty solution for the issue described in: ColdFusion 8 Exception Handling Breaks HTTP Requests.

<cffunction name="onError" access="public" returntype="void" output="false">
 <cfargument name="exception" type="any" required="true">
 <cfargument name="eventname" type="string" required="false">
 
 <cfset var error = getMetaData(exception)>
 <cfset var message = left(reReplace(reReplace(exception.message,"\r|\n"," ","all"),"\s\s+"," ","all"),500)>
 <cfset var msg = "">
 
 <cfloop condition="true">
 <cfif not isDefined("error") or error.getName() eq "coldfusion.runtime.NeoException">
 <cfbreak>
 </cfif>
 <cfset error = error.getSuperClass()>
 </cfloop>
 
 <cfif isDefined("error")>
  <cfset msg = error.getDeclaredField("msg")>
  <cfset msg.setAccessible(true)>
  <cfset msg.set(exception,message)>

  <cfif exception.getClass().getName() eq "coldfusion.runtime.CustomException">
  <cfset msg = getMetaData(exception).getDeclaredField("userMessage")>
  <cfset msg.setAccessible(true)>
  <cfset msg.set(exception,message)>
  </cfif>
 </cfif>
 
 <cfthrow object="#exception#">
</cffunction>

Place that in your Application.cfc and CF won’t break the http requests anymore. Of course this won’t work if you have the Java Access Control enabled in the CF8 Administrator.

ColdFusion 8 Exception Handling Breaks HTTP Requests

August 1, 2007 on 2:52 am | In Programming, Adobe, ColdFusion | 1 Comment

Just found this bug today….

So CF8 outputs the cfcatch.message into the Reason-Phrase portion of the HTTP Response, however it does not strip new lines (LF or CR). A web server, however, should never send new lines in the Reason-Phrase [1], and should probably be truncating that error message at a certain length.

[1] RFC2616, Section6, HTTP Response

It’s pretty easy to reproduce this bug:

<cfthrow message="foo #chr(10)##chr(10)##chr(10)# bar">

Another way to show this is with the new deserializeJSON() function in CF8 when the JSON is not valid. CF outputs the exception message with the JSON into the Reason-Phrase portion of the HTTP response Status-Line without stripping out new lines.

ColdFusion Code

<cfset json = '
{
    "foo": [
        {}
        "",
        {
            "f": {}
        }
    ]
}
'>

<cfset deserializeJSON(json)>

And the server responds with:

HTTP Response

HTTP/1.1 500 JSON parsing failure: Expected ',' or ']' at character 20:'"' in {
	"foo": [
		{}
		"",
		{
			"f": {}
		}
	]
}
Date: Wed, 01 Aug 2007 05:31:39 GMT
Server: Apache/1.3.33 (Darwin) mod_fastcgi/2.4.2 PHP/5.2.0 JRun/4.0
server-error: true
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8

<!-- " ---></TD></TD></TD></TH></TH></TH></TR></TR></TR></TABLE></TABLE>

As it stands now, if you had 100 lines of JSON and there’s an error at the end, CF will dump all previous lines of JSON into the http Reason-Phrase.

This is particularly apparent in Safari (and WebKit based browsers) where it actually displays the HTTP headers in the body of the page because it sees new lines and assumes the HTTP headers are complete, and worse in Gecko based browsers that render the page as text/plain because the Content-Type header is never processed!

It should also be noted that CF7 output “Internal Server Error” for the Reason-Phrase instead of the exception message.

There also seems to be some other random junk thrown into the page when an exception is thrown….

foo bar baz<cfthrow message="foo #chr(10)##chr(10)#bar">

Will generate the following right after the http headers:

b
foo bar baz
1f27

I hope this saves someone some time trying to figure out what’s going on on their code! :)

Getting the Expected Results for GetCurrentTemplatePath() in a Custom Tag.

July 17, 2007 on 5:43 pm | In Programming, Java, Adobe, ColdFusion | 4 Comments

While working on the template system used for the conference websites I ran across a problem where I needed the path to the template that called a custom tag. The first thing I tried was getCurrentTemplatePath() thinking that it might return that since the documentation makes no mention of custom tags. Instead, however, the function returns the path to the custom tag itself.

Ben Nadel noticed some of this odd behavior as well.

I spent a long time trying to figure out how to get the caller template path, including what Ben did which was to add a special function to the caller scope.

<cfscript>
function getCallerTemplatePath() {
    return getCurrentTemplatePath();
}
caller.getCallerTemplatePath = getCallerTemplatePath;
path = caller.getCallerTemplatePath();
</cfscript>

This doesn’t work though. Instead I still got the template path of the custom tag!

I dug around in the PageContext (which is returned from getPageContext() if you’re not familiar) with no luck and finally gave up resorting to this…

/**
    Monumental hack, but the only way I could figure out how to do
    a getCurrentTemplatePath() like call that resolves to the page
    that called this custom tag.
*/
function getCallerTemplatePath() {
    try {
       error;
    } catch( any cfcatch ) {
        return cfcatch.tagContext[3].template;
    }
}

Which worked but really felt like a hack since it means throwing an exception on every request. So I kept an eye out as I dug around in the internals of the CF engine for various other things, and today I was rewarded with an awesome solution.

/** Gets the path to the page that called this custom tag. */
function getCallerTemplatePath() {
    var field = getMetaData(caller).getDeclaredField("pageContext");
    field.setAccessible(true);
    return field.get(caller).getPage().getCurrentTemplatePath();
}

Now to get at why and how this kind of thing works…

Inside the ColdFusion runtime the foundation unit for all scripts, components and tags is the coldfusion.runtime.CFPage object, and the getCurrentTemplatePath() function is really identical to…

function getCurrentTemplatePath() {
    return getPageContext().getPage().getCurrentTemplatePath();
}

After realizing this it dawned on me that the custom tags, cfcs, and pages all have their own PageContext and Page objects, and as such the template path is going to be different, or rather bound, to the page in which the function is called from, not where it’s defined.

Knowing this I was able to grab the page context out of the caller scope, which is the page context of the caller, and not the current page, and use that to get the current template path of the page for which that page context operates.

Also, for those who aren’t familiar, the getMetaData() function can be used to return the java.lang.Class instance for most objects you wouldn’t normally be able to call getClass() on in ColdFusion. For instance you can call getMetaData(variables).getName() and you’ll get coldfusion.runtime.VariableScope.

Doing this really made my code feel less icky, so I hope this is useful to someone else.

(PS, Tested and works on CF6+ and CF7+, anyone have CF8?)

Entries and comments feeds. Valid XHTML and CSS. ^Top^