void IHttpHandler.ProcessRequest(HttpContext context) { var url = EwfApp.GetRequestAppRelativeUrl(context.Request); var queryIndex = url.IndexOf("?", StringComparison.Ordinal); if (queryIndex >= 0) { url = url.Remove(queryIndex); } var extensionIndex = url.LastIndexOf(".", StringComparison.Ordinal); var versionStringOrFileExtensionIndex = extensionIndex; var urlVersionString = ""; if (url.StartsWith(VersionedFilesFolderName + "/") || url.StartsWith(EwfFolderName + "/" + VersionedFilesFolderName + "/")) { urlVersionString = "invariant"; } else { // We assume that all URL version strings will have the same length as the format string. var prefixedVersionStringIndex = extensionIndex - (urlVersionStringPrefix.Length + EwfSafeResponseWriter.UrlVersionStringFormat.Length); if (prefixedVersionStringIndex >= 0) { DateTimeOffset dateAndTime; var versionString = url.Substring(prefixedVersionStringIndex + urlVersionStringPrefix.Length, EwfSafeResponseWriter.UrlVersionStringFormat.Length); if (DateTimeOffset.TryParseExact( versionString, EwfSafeResponseWriter.UrlVersionStringFormat, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.None, out dateAndTime)) { versionStringOrFileExtensionIndex = prefixedVersionStringIndex; urlVersionString = versionString; } } } if (versionStringOrFileExtensionIndex < 0) { throw new ResourceNotAvailableException("Failed to find the extension in the URL.", null); } var extension = url.Substring(extensionIndex); var staticFileInfo = EwfApp.GlobalType.Assembly.CreateInstance( CombineNamespacesAndProcessEwfIfNecessary( EwfApp.GlobalType.Namespace, (url.Remove(versionStringOrFileExtensionIndex) + extension.CapitalizeString()).Separate("/", false) .Select(StandardLibraryMethods.GetCSharpIdentifier) .Aggregate((a, b) => a + "." + b) + "+Info")) as StaticFileInfo; if (staticFileInfo == null) { throw new ResourceNotAvailableException("Failed to create an Info object for the request.", null); } var mediaTypeOverride = EwfApp.Instance.GetMediaTypeOverrides().SingleOrDefault(i => i.FileExtension == extension); var contentType = mediaTypeOverride != null ? mediaTypeOverride.MediaType : MimeTypeMap.MimeTypeMap.GetMimeType(extension); Func <string> cacheKeyGetter = () => staticFileInfo.GetUrl(false, false, false); EwfSafeResponseWriter responseWriter; if (contentType == ContentTypes.Css) { Func <string> cssGetter = () => File.ReadAllText(staticFileInfo.FilePath); responseWriter = urlVersionString.Any() ? new EwfSafeResponseWriter( cssGetter, urlVersionString, () => new ResponseMemoryCachingSetup(cacheKeyGetter(), staticFileInfo.GetResourceLastModificationDateAndTime())) : new EwfSafeResponseWriter( () => new EwfResponse(ContentTypes.Css, new EwfResponseBodyCreator(() => CssPreprocessor.TransformCssFile(cssGetter()))), staticFileInfo.GetResourceLastModificationDateAndTime(), memoryCacheKeyGetter: cacheKeyGetter); } else { Func <EwfResponse> responseCreator = () => new EwfResponse( contentType, new EwfResponseBodyCreator( responseStream => { using (var fileStream = File.OpenRead(staticFileInfo.FilePath)) IoMethods.CopyStream(fileStream, responseStream); })); responseWriter = urlVersionString.Any() ? new EwfSafeResponseWriter( responseCreator, urlVersionString, memoryCachingSetupGetter: () => new ResponseMemoryCachingSetup(cacheKeyGetter(), staticFileInfo.GetResourceLastModificationDateAndTime())) : new EwfSafeResponseWriter( responseCreator, staticFileInfo.GetResourceLastModificationDateAndTime(), memoryCacheKeyGetter: cacheKeyGetter); } responseWriter.WriteResponse(); }
/// <summary> /// Creates a response writer with CSS text. /// </summary> /// <param name="cssGetter">A function that gets the CSS that will be preprocessed and used as the response. Do not pass or return null.</param> /// <param name="urlVersionString">The resource-version string from the request URL. Do not pass null or the empty string; this parameter is required /// because it greatly improves cacheability, which is important for CSS. You must change the URL when the CSS changes, and you must not vary the response /// based on non-URL elements of the request, such as the authenticated user.</param> /// <param name="memoryCachingSetupGetter">A function that gets the memory-caching setup object for the response. Do not pass or return null; memory caching /// is important for CSS and is therefore required.</param> public EwfSafeResponseWriter(Func <string> cssGetter, string urlVersionString, Func <ResponseMemoryCachingSetup> memoryCachingSetupGetter) { var memoryCachingSetup = new Lazy <ResponseMemoryCachingSetup>(memoryCachingSetupGetter); writer = createWriter( () => new EwfResponse(ContentTypes.Css, new EwfResponseBodyCreator(() => CssPreprocessor.TransformCssFile(cssGetter()))), urlVersionString, "", () => memoryCachingSetup.Value.LastModificationDateAndTime, () => memoryCachingSetup.Value.CacheKey); }