Search code examples
coldfusioncoldfusion-9

How to keep track of how many requests are tied to cfcontent serving files?


Since APE's mod_xsendfile does not work with CF9's jrun_iis6_wildcard.dll, I'm left with serving files securely using <cfcontent>. The problem now is that if the file download is large, or the connection is slow, it will tie up a CF request for a long period of time. Without a way to enforce a hard limit, one can bring down the CF server in theory with all the requests tied up with serving files.

I tried doing extra logging / logic below <cfcontent file=""> but I noticed that they are never reached and executed.

<cfcontent file="test.mp3">

<!--- won't reach here --->
<cfdump output="console" var="#now()# download done!">

What can one do to avoid CF being brought down by handling too many cfcontent requests?

Update: good news! CF10 works with APE's mod_xsendfile!


Solution

  • Solution 1

    Considering that you'll be highly unlikely to have a 100% true accounting due to uncontrollable factors (threads that get "stuck", service/server shutdown, etc) you could do the following:

    If you only want to keep track of total requests you can use an application variable that you increment when beginning to serve the file. Then when the content is done you decrement the count. However, you'll want to take care to use cflock to ensure that this update doesn't cause any issues.

    If you wanted to log this to a file you can do the same thing but still wrap it in a cflock to ensure that you don't run into any issues with the requests simultaneously reading/writing the file.

    If you're using SQL you could create a table to represent the files and for each fetch add a record and appropriate info

    • filename
    • completed as a bit yes/no field defaulted to false
    • user/client info
    • start date/time defaulted to now,
    • end date/time default to null,
    • status "downloading"
    • any other info

    Using the returned identity cfcontent the file and then when done do an update to the table with the specified ID with the correct date/time and status "success" and completed to yes.

    During onerror you can update the table to reflect the status "error [associated error details]" and completed to 1. It wouldn't be a bad idea to add a catchall update to change to completed = 1 or to purge records that are not available (maybe during application onstartup or after a period of time)

    This will allow you to query this table for total currently pending requests (and what they are, etc.)

    However, that only addresses the issue of the long running requests.

    Solution 2

    Ideally the issue is to securely return the file content. Depending on just how sensitive the files are (e.g. preferred private but not end of the world if not) you could "copy" them to an appropriately web accessible directory but using a UUID for the name. So let's say it is Secret1.pdf you would create a directory using cfdirectory with the file then copied into it. Giving you something like this:

    /files/xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx/Secret1.pdf and then do a to redirect to that directory.

    You can then setup a scheduled task or gateway or whatever method you prefer to purge directories that are older than a set number of hours. E.g. to delete directory xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx and all it's files 30 minutes from now for example.