URL Rewriting And ColdFusion's WriteToBrowser Image Functionality (CFFileServlet)
Posted March 5, 2010 at 9:38 AM by Ben Nadel
Yesterday, as I was experimenting with drawing on an HTML canvas element with jQuery, I was using ColdFusion to render temporary images to the browser. Specifically, I was using the CFImage tag's "WriteToBrowser" action to create a temporary PNG file to be served up by ColdFusion's CFFileServlet. This action creates a image file with the given type of location:
/CFFileServlet/_cf_image/_cfimg-1234567890.PNG
When I first used this approach, none of the temporary ColdFusion images were loading; they were all coming up as 404 file-not-found errors. After a few minutes of confusion, I finally figure out what was going on - my URL rewriting was blocking these temporary image requests:
- RewriteCond %{REQUEST_FILENAME} !-f
- RewriteCond %{REQUEST_FILENAME} !-d
- RewriteRule ^(.+)$ index.cfm/$1 [NC,L,QSA]
As you can see, this rewrite rule gets applied if the requested file is neither a valid file nor a valid directory. Since the ColdFusion CFFileServlet directory doesn't exist in a physical way, my URL rewriting was redirecting the request over to my front-controller (which was then trying to evaluate it as an action).
To get around this, I had to add a rewrite condition to my IIS MOD-Rewrite access file to ignore the rewrite if the requested file was in the CFFileServlet directory:
- RewriteCond %{REQUEST_FILENAME} !-f
- RewriteCond %{REQUEST_FILENAME} !-d
-
- # Allow CFFileServlet requests through since they are Voodoo!
- RewriteCond %{REQUEST_URI} !(?i)^[\\/]CFFileServlet
-
- RewriteRule ^(.+)$ index.cfm/$1 [NC,L,QSA]
With this IIS-MOD Rewrite condition in place, the ColdFusion temporary images started showing up quite nicely. Notice that the rewrite condition checks the REQUEST_URI variable, not the REQUEST_FILENAME. This is because the REQUEST_FILENAME give us the full file path on the server; we can't use this because we only want to allow URLs with the root directory, "CFFileServlet". As such, we need to check the REQUEST_URI, which gives us the script name off of the server.
Reader Comments
I found the exact same issue with using <CFCHART> and the CFIDE directory. CFCHART doesn't actually need access to CFIDE, the servletfilter just needs to work.
@Shannon,
Ah, good call. I have not done too much with charting. I assume it's using the same temporary image servlet then?
the charts end up using a URL like this:
/CFIDE/GraphData.cfm?graphCache=someval&graphID=Images/abiglongnumber.SWF
I solved the problem by creating an empty "CFIDE" directory in the root of my site.
For multihomed web servers it's useful to create an alias to avoid resolving the same issue over and over.
Apache rule is
Alias /CFFileServlet {ColdFusion dir}/tmpCache/CFFileServlet"
For IIS there should be something under admin for creating virtual directories...
This is also true for the CF Administrator, RDS (and Remoting, I think). All of these are disconnected from the need to have actual physical files on the filesystem. RDS and perhaps Remoting will break if you enable a "verify if file exists" option using either a rewrite rule or the IIS configuration option.
@Shannon, @Jura, @Dave,
I gotcha - so just having the directory there gives the pipeline something to hook into (even if it's not using any of the local files). Makes sense.
Our application framework uses 404 handling to create web friendly URLs and serve all sorts of mime types. It's nice to have all the logic for serving pages inside the framework itself (rather than Apache/IIS), but causes issues in getting/parsing post data.
Anyways, we run into similar issues and I try at all costs to avoid using the default ColdFusion file servlets. When possible, I end up making my own handlers by handling the bytearrays myself.
One of my bigger grips with ColdFusion is that it wants to "simplify" too much sometimes without giving options for handling it yourself if you wish to do so (i.e. no CF I don't want you to create the bytearray AND serve it/write it to disk, give it back to me and I will handle it). Most of the newer tags support bytearrays for input but some still want to handle serving the file or writing to the file system... Ugh.
@Rocky,
Yeah, I know what you mean re: form posts. 404 or otherwise, when I do a form post, I typically drop out of my SES mode and revert back to front-controller / action-variable-based URLs.
As far as the direct byte array file handling, I think we may have touched on this before on some other posts. Like you, I definitely enjoy the fact that many newer tags allow binary variables to be passed-in; there's something that just feels nice about that. As far as the way CF handles the file posting, however, I've personally never found it to be too much of an issue (not to diminish in anyway that it might cause issues for you). I have heard a number of people make comments along the same lines, so it's clearly a valid concern.
@Ben
We, finally, have been able to convert all URL and FORM variables inside the framework itself (via getHttpRequestData()). The hardest part was parsing the bytearray sent when a file is uploaded along with other form variables without corrupting the data itself.
As to the bytearray and CF tags. It's not a concern per-se, just more of a feature I wish was available more often. :)
I'm using multisite (http://www.hairy-spider.com/post/Multisite.aspx) to run multiple simultaneous websites on my XP machine, and can't find a way to get this to work.... When I add a Virtual Directory to the Default Website in IIS, I still can't see the images. Any thoughts?
Do you have "check if file exists" enabled? If so, this will break.
@Eric,
I've only done a small bit of experimenting with getting XP to perform like a "true" server and it was never very straightforward.
if I use Apache. is it same the script like this :
RewriteCond %{REQUEST_URI} !(?i)^[\\/]CFFileServlet
I have added a rule to convert all to lower case in IIS7 and the cfimage not displaying how can I add the rule for IIS7 Thank you



