Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at RIA Unleashed (Nov. 2010) with: Bob Silverberg

URL Rewriting And ColdFusion's WriteToBrowser Image Functionality (CFFileServlet)

By Ben Nadel on
Tags: ColdFusion

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. :)

@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.

@Mounir,

Open your lower case URL Rewrite rule and add the following condition.

Condition input: {REQUEST_URI}
Check if input string: Does Not Match the Pattern
Pattern: ^/CFFileServlet/_cf_captcha/

Jason,

In my case without ColdBox, only when I created captchas by cfimage, I had the same issue as Mounir. Other images by cfimage seemed to be fine, so I only needed to take care of the path "/CFFileServlet/_cf_captcha/."

Since it didn't work for your case, using "/CFFileServlet/" should take care of everything referencing to the path. Currently there are only two folders "_cf_captcha" and "_cf_image" under "CFFileServlet" folder, so it doesn't matter, but if you want to be more specific, you can just add another pattern "^/CFFileServlet/_cf_image/" and select "Match All" for "Logical grouping" to do the same thing.

This is an old thread, but I discovered it via googles and wanted to add how I fixed it in my configuration.

Our IIS 7.5 (on Windows Server 2008) infrastructure is three-layer. All inside and outside requests are sent by our DNS to the ARR (Application Request Routing) server (we call it the 'pirate' server), which has URL rewrite rules to redirect to the actual servers in layer 2 (in a protected subnet).

So a request for http://subdomain.somesite.com has a URL rewrite rule of http://cf9.somesite.com/subdomain{REQUEST_URI}.

The 'pirate' server DNS resolves the cf9.somesite.com to the actual CF9 server (called cf9.somesite.com) in our layer 2/protected DMZ.

The cf9.somesite.com IIS site (on the server in the layer 2/protected DMZ subnet) has a subfolder for 'subdomain'. So a request for a temporary image eventually resolves to cf9.somesite.com/subdomain/CFFileServeLet/_cf_image/_1234.png (where "_1234.png" is the temporary PNG filename that CF creates).

To make all of that work, we had to create two virtual directories in the 'subdomain' folder: one for 'CFFileServlet', and a virtual directory under that for '_cf_image'.

That allows the request for cf9.somesite.com/subdomain/CFFileServeLet/_cf_image/_1234.png to be found.

All of that works just fine in our environment. Hope it helps others.

Hi Ben,

I have a 2 instance cluster (CF 10) with apache as the web server.

The <cfimage action="writeToBrowser" writes the file to C:\ColdFusion10\cfdevcb1\runtime\conf OR C:\ColdFusion10\cfdevcb2\runtime\conf depending on which instance the user is on.

The html output by the CF Tag is: <img alt="" src="/CFFileServlet/_cf_image/_cfimg-3698071103735262507.PNG"> which gets a 404.

If I could change the temp location (where files are written) to C:\ColdFusion10\cfusion\tmpCache then I could create an alias that pointed to that. However, I can't see how to change the temp location.

Any ideas?

Craig

I did something similar in IIS URL Rewrite module but I asked it not to apply its rewrite rule if the pattern matched ^(.*).PNG

The coldfusion images worked fine then

We are having the same issue, and trying to find a solution.

We tried:
Condition input: {REQUEST_URI}
Check if input string: Does Not Match the Pattern
Pattern: ^/CFFileServlet/_cf_captcha/

That did not work, any suggestions??