Something I've learned over the course of many years working in IT is that when you hit a difficult to explain problem it's very easy to say "it's the runtime's fault!" or "that's a compiler bug" to cover for the lack of explanation for your problem. The vast majority of the time, it's not true though. It's just a subtler bug in your own work that you can't see yet.
Every so often, however, it is true. And it turns out the issue I discussed the other week about Sitecore rendering a Razor error when you asked for a media item may well be an example of this.
When I wrote my previous post, my colleagues and I had worked out how to resolve the problem we saw, but didn't understand what the underlying issue that caused it actually was. Since then one of my colleagues has spent further time discussing our situation with the team at Sitecore Support and they've provided some really helpful feedback about what the underlying issue might be. And the surprise is that they're pinning it on a .Net Framework bug.
Their explanation describes a particular set of circumstances.
Each request you make goes through
System.Web.WebPages.WebPageHttpModule
which eventually calls
System.Web.WebPages.WebPageRoute.MatchRequest()
. Part of the logic inside that method calls
WebPageRoute.FileExists()
. That in turn depends on
System.Web.Util.FileUtil.IsSuspiciousPhysicalPath()
to look for some common scenarios that might indicate a malicious request. If all that succeeds, our media requests should end up with the custom handler that Sitecore provides for these URLs. But in the scenario we discovered the custom handler wasn't called – but .Net's Razor handler was instead.
In our particular situation, if the odd file "NOT_A_VALID_FILESYSTEM_PATH" existed in the website root, and the
config setting for "relaxedUrlToFileSystemMapping"
is set to
True
, then the
IsSuspiciousPhysicalPath()
method can mess things up when the path being processed is a certain length.
Support's example was:
The next URL is requested:
http://a-test-server.local/~/media/Client-Name/print-resource-images/thumbnails/elected-representatives/Campaign-factsheet-Thumbnail-Nov-16-v3.ashx
CustomHandlers processor modifies the URL. Its current value is
http://a-test-server.local/~/media/Client-Name/print-resource-images/thumbnails/elected-representatives/sitecore_media.ashx/~/media/Client-Name/print-resource-images/thumbnails/elected-representatives/Campaign-factsheet-Thumbnail-Nov-16-v3.ashx
IsSuspiciousPhysicalPath()
method is triggered. Physical path isC:\Inetpub\wwwroot\a-test-server\Website\~\media\Client-Name\print-resource-images\thumbnails\elected-representatives\sitecore_media.ashx\~\media\Client-Name\print-resource-images\thumbnails\elected-representatives\Campaign-factsheet-Thumbnail-Nov-16-v3.ashx
Please note that/en
s are not included in physicalPath even if they are included in your request URL.physicalPath.Length is 258. The value of
FileExists
is "false".
GetRouteLevelMatch(...)
modifies the URL. Its current value ishttp://a-test-server.local/~/media/Client-Name/print-resource-images/thumbnails/elected-representatives/sitecore_media.ashx/~/media/Client-Name/print-resource-images/thumbnails/elected-representatives/Campaign-factsheet-Thumbnail-Nov-16-v3.ashx.cshtml
IsSuspiciousPhysicalPath()
method is triggered. Physical path isC:\Inetpub\wwwroot\a-test-server\Website\~\media\Client-Name\print-resource-images\thumbnails\elected-representatives\sitecore_media.ashx\~\media\Client-Name\print-resource-images\thumbnails\elected-representatives\Campaign-factsheet-Thumbnail-Nov-16-v3.ashx.cshtml
physicalPath.Length is 265. The value of
FileExists
is "true". The path has a file extension, so the media item (NOT_A_VALID_FILESYSTEM_PATH
file to be precise) is rendered as a razor view.If the initial length of "physicalPath" string was 245,
/default.cshtml
would be added.
This is a bit complicated, but working through it with the public source for the relevant bits of .Net does seem to explain the odd behaviour we saw. Including the bit where changing the length of the URL could fix the problem, but certain invalid URLs would not return the expected 404.
Support have raised an issue with Microsoft to get the underlying bug investigated and resolved – so hopefully that will get sorted in a future update to the .Net runtime. They've also marked this as an issue in Sitecore using the bug number 95341 – so if you hit a similar issue that's the number to report to Support.
And in the meantime, keep an eye out for
NOT_A_VALID_FILESYSTEM_PATH
getting accidentally created if
Server.MapPath()
processes URLs with invalid characters in it...