The continuing saga of StaticFileHandler - meet DefaultHttpHandler
Categories
I bloody well love Reflector. It's just magic.
After discovering that StaticFileHandler doesn't handle conditional gets and ranges, I've dug a little deeper, and, unsurprisingly, the plot thickens.
In .net 1.x, you could use StaticFileHandler to serve static files from an asp.net application - just use the IIS wildcard mapping so that all files went through the asp.net ISAPI dll, and modify your web.config.
In .net 2, things are a little better. Now, the global web.config file catches any GET, HEAD or POST requests to any file that hasn't already been handled and passes them off to DefaultHttpHandler, not StaticFileHandler. (Any other verbs get passed to HttpMethodNotAllowedHandler. That one's internal. 3 guesses what it does?)
This is quite a nice class, at least in theory. It's an asynchronous http handler that will serve static files. The bad news is that it serves static files using StaticFileHandler, with all the issues that has (no support for conditional gets or ranges). But the good news is that if you haven't modified any headers (such as caching) and you haven't already written something to the response stream, and the response stream doesn't have a filter (such as compression) and you're running in process in IIS6 then the request is passed back to IIS for processing. IIS will do the decent thing, and serve the static file with support for conditional gets and ranges and all will be good. If any of that exhaustive list is not true, then StaticFileHandler gets to serve the content (boo, hiss!). Note that you can still get compression, but you'll have to configure it at the IIS level now, not the HttpModule level. That's the good news.
This might seem of limited use - if you can't modify the headers, or add a compression filter to the output stream, what's the point? Well, you can monitor and log the request, for one thing. And more importantly, you can derive from the public DefaultHttpHandler and override the virtual OverrideExecuteUrlPath to route you off to somewhere else and IIS will serve it (sounds just like I was trying to do originally!)
Unfortunately, this class has it's problems, too. It doesn't allow you to route to your own static file handler. Even worse, though, is that you can only specify an override of the path when it decides (via conditions outside of your derived class's control) that IIS should serve the file. If it decides that StaticFileHandler should serve it, you have to have implicit knowledge of the inner workings of the DefaultHttpHandler class and know to do a Context.RewritePath in OnExecuteUrlPreconditionFailure. This is mentioned (albeit obliquely) in the docs for OverrideExecuteUrlPath. And I can't roll my own version of this as it uses internal methods to pass control back to IIS.
As long as you're strict about your global setup, this might be useful. I'll have to do a test to see if it'll fit my requirements, but this feels a little fragile - I really don't want it falling back to StaticFileHandler. I think I'll follow up on the Virtual Path Provider idea, or just buckle down and write a BetterStaticFileHandler.