The good news is that the problem can be solved using the simple LOCALURL attribute. The bad news is that you have to do it at all, and that if you don't do it, it can have such unfortunate and unexpected impact. (And just as bad, again, is that hardly anyone has talked about it.) This entry will elaborate on the issue (and a couple of other possible CFDocument performance issues, as a bonus.)
I've been meaning to write about the importance of this problem and solution (the LocalURL attribute) for a long time (it came out in CF8). Often when I'm helping people with CF troubleshooting problems, whether on mailing lists or in my consulting services, I've been able to show that long-running requests (or an unexpectedly excessive number of requests) were sometimes due to this very problem.
Basics of the LocalURL attribute
Before we go any further, let's start with the details of the attribute (which may surprise many). The following is extracted from a larger blog entry about various CFDocument improvements in CF8 from Adobe Engineer, Rupesh Kumar, back in 2007:
When CFDocument body contains a relative URL, ColdFusion will resolve the relative URL to an absolute URL and will send an HTTP request for this url [emphasis, mine]. A side effect of this is Server ends up sending HTTP request even for local URL or images that are lying on the local file system which obviously hurts the performance. In ColdFusion 8, we have added a new attribute "localURL" to cfdocument tag which if enabled, will try to resolve the relative URLs as file on the local machine.
- localURL : "true" | "false" It should be enabled if the images used in cfdocument body are on the local machine. This would make the cfdocument engine retrieve the images directly from the file system rather then asking the server for it over http
This attribute helps reducing the load from the server so that the same web server thread can now serve user request instead of serving local images to CFDocument. This also addresses some of the "missing image" problems which I mentioned here. Here is a sample code using this attribute.
<cfdocument format="PDF" localUrl="true">
So why is this an issue?
It would help to make a point of clarification: CFDOCUMENT builds a document (perhaps a PDF or Word doc) on the server, from whatever CFML and/or HTML is within the tags.
As such, CF will need to "get" whatever images (or scripts or css files) are defined on the generated HTML page (as img src, script src, link href, etc.) so it can build the resulting "document" file on the server.
And the point of the dilemma (identified on this page) is that a single CFDOCUMENT with many such img src (or similar) tags will not just cause CF to look to the file system to get the files they point to. Instead, CF will get them via CFHTTP.
Technically, the issue is that CF doesn't necessarily "know" that the location pointed to in the img src and similar tags *is* on the local server. So it presumes it has to get ANY of them using a CFHTTP call. That's what causes the problem, if there are many of them. Using the LOCALURL attribute tells CF instead that it SHOULD look for the files on the local filesystem and NOT do a CFHTTP to get them.
Sadly, this issue is only barely mentioned in the CF Docs page on CFDocument, and it would be easy to miss the point it's trying to make. (It says only that CF "requests the server for images over HTTP even though the image files are stored locally".)
How some tried to workaround the problem with file:// references
While looking around to see who else maybe had talked about this fix (which, as I noted, I found virtually no other references to it), I did find that some people had effectively "solved" the problem by telling CF to use "file:///" protocol references in the img src and similar tags.
Among the entries discussing this were:
- Including Images in a PDF created in CFDOCUMENT
- CFDocument performance
- You CAN Use the File System With Cfdocument (Who Knew)
It's understandable that people figured it out as a work-around, and perhaps someone even started sharing the idea before CF8 added this attribute, but the LOCALURL would seem generally the way to go.
Some other CFDOCUMENT performance resources
Though not related to the LocalURL attribute, there are some other things that may lead to performance problems.
First, those on CF Standard (as opposed to Enterprise or Developer edition) should know that CFDocument is one of several tags that are single-threaded through CF's "Enterprise Feature Router" (EFR).
Second, there are certainly still other possible CFDocument performance issues, and the following other resources address some of those:
- Cfdocument and Performance, from Mark Kruger
- Images and CFDocument performance, also by Rupesh Kumar
- A workaround for cfdocument missing images, by Rupesh Kumar
- Missing images in CFDocument, by Rupesh Kumar
Hope any or all of the info above may be helpful to some readers. Let me know what you think.