ScriptResourceHandler.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / Orcas / RTM / ndp / fx / src / xsp / System / Web / Extensions / Handlers / ScriptResourceHandler.cs / 2 / ScriptResourceHandler.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Web.Handlers { 
    using System; 
    using System.Collections;
    using System.Collections.Generic; 
    using System.Collections.Specialized;
    using System.Globalization;
    using System.IO;
    using System.IO.Compression; 
    using System.Reflection;
    using System.Resources; 
    using System.Security; 
    using System.Security.Cryptography;
    using System.Security.Permissions; 
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Threading;
    using System.Web; 
    using System.Web.UI;
    using System.Web.Configuration; 
    using System.Web.Handlers; 
    using System.Web.Hosting;
 
    using System.Web.Script.Serialization;
    using System.Web.Resources;
    using System.Web.Util;
 
    using Debug = System.Diagnostics.Debug;
 
    [ 
    AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal),
    AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal), 
    ]
    public class ScriptResourceHandler : IHttpHandler {

        private const string _scriptResourceUrl = "~/ScriptResource.axd"; 
        private static readonly IDictionary _assemblyInfoCache = Hashtable.Synchronized(new Hashtable());
        private static readonly IDictionary _cultureCache = Hashtable.Synchronized(new Hashtable()); 
        private static readonly Object _getMethodLock = new Object(); 
        private static MethodInfo _getWebResourceUrl;
        private static IScriptResourceHandler _scriptResourceHandler = new RuntimeScriptResourceHandler(); 
        private static string _scriptResourceAbsolutePath;

        private static string ScriptResourceAbsolutePath {
            get { 
                if (_scriptResourceAbsolutePath == null) {
                    _scriptResourceAbsolutePath = VirtualPathUtility.ToAbsolute(_scriptResourceUrl); 
                } 
                return _scriptResourceAbsolutePath;
            } 
        }

        private static Exception Create404(Exception innerException) {
            return new HttpException(404, AtlasWeb.ScriptResourceHandler_InvalidRequest, innerException); 
        }
 
        private static string DecryptParameter(NameValueCollection queryString) { 
            string encryptedData = queryString["d"];
            if (String.IsNullOrEmpty(encryptedData)) { 
                Throw404();
            }

            try { 
                return Page.DecryptString(encryptedData);
            } 
            catch (CryptographicException ex) { 
                throw Create404(ex);
            } 
        }

        internal static CultureInfo DetermineNearestAvailableCulture(
            Assembly assembly, 
            string scriptResourceName,
            CultureInfo culture) { 
 
            if (String.IsNullOrEmpty(scriptResourceName)) return CultureInfo.InvariantCulture;
 
            Tuple cacheKey = new Tuple(assembly, scriptResourceName, culture);
            CultureInfo cachedCulture = (CultureInfo)_cultureCache[cacheKey];
            if (cachedCulture == null) {
 
                string releaseResourceName =
                    scriptResourceName.EndsWith(".debug.js", StringComparison.OrdinalIgnoreCase) ? 
                    scriptResourceName.Substring(0, scriptResourceName.Length - 9) + ".js" : 
                    null;
 
                ScriptResourceInfo resourceInfo = ScriptResourceInfo.GetInstance(assembly, scriptResourceName);
                ScriptResourceInfo releaseResourceInfo = (releaseResourceName != null) ?
                    ScriptResourceInfo.GetInstance(assembly, releaseResourceName) : null;
 
                if (!String.IsNullOrEmpty(resourceInfo.ScriptResourceName) ||
                    ((releaseResourceInfo != null) && !String.IsNullOrEmpty(releaseResourceInfo.ScriptResourceName))) { 
 
                    ResourceManager resourceManager =
                        ScriptResourceAttribute.GetResourceManager(resourceInfo.ScriptResourceName, assembly); 
                    ResourceManager releaseResourceManager = (releaseResourceInfo != null) ?
                        ScriptResourceAttribute.GetResourceManager(releaseResourceInfo.ScriptResourceName, assembly) : null;

                    ResourceSet localizedSet = null; 
                    ResourceSet releaseSet = null;
                    if (resourceManager != null) { 
                        resourceManager.GetResourceSet(CultureInfo.InvariantCulture, true, true); 
                        // Look for the explicitly localized version of the resources that is nearest the culture.
                        localizedSet = resourceManager.GetResourceSet(culture, true, false); 
                    }
                    if (releaseResourceManager != null) {
                        releaseResourceManager.GetResourceSet(CultureInfo.InvariantCulture, true, true);
                        // Look for the explicitly localized version of the resources that is nearest the culture. 
                        releaseSet = releaseResourceManager.GetResourceSet(culture, true, false);
                    } 
                    if ((resourceManager != null) || (releaseResourceManager != null)) { 
                        while ((localizedSet == null) && (releaseSet == null)) {
                            culture = culture.Parent; 
                            if (culture.Equals(CultureInfo.InvariantCulture)) break;
                            localizedSet = resourceManager.GetResourceSet(culture, true, false);
                            releaseSet = (releaseResourceManager != null) ?
                                releaseResourceManager.GetResourceSet(culture, true, false) : null; 
                        }
                    } 
                    else { 
                        culture = CultureInfo.InvariantCulture;
                    } 
                }
                else {
                    culture = CultureInfo.InvariantCulture;
                } 
                cachedCulture = culture;
                _cultureCache[cacheKey] = cachedCulture; 
            } 
            return cachedCulture;
        } 

        private static void EnsureScriptResourceRequest(string path) {
            if (!IsScriptResourceRequest(path)) {
                Throw404(); 
            }
        } 
 
        private static Assembly GetAssembly(string assemblyName) {
            string[] parts = assemblyName.Split(','); 

            if ((parts.Length != 1) && (parts.Length != 4)) {
                Throw404();
            } 

            AssemblyName realName = new AssemblyName(); 
            realName.Name = parts[0]; 
            if (parts.Length == 4) {
                realName.Version = new Version(parts[1]); 
                string cultureString = parts[2];
                realName.CultureInfo = (cultureString.Length > 0) ?
                    new CultureInfo(cultureString) :
                    CultureInfo.InvariantCulture; 
                realName.SetPublicKeyToken(HexParser.Parse(parts[3]));
            } 
            Assembly assembly = null; 
            try {
                assembly = Assembly.Load(realName); 
            }
            catch (FileNotFoundException fnf) {
                Throw404(fnf);
            } 
            catch (FileLoadException fl) {
                Throw404(fl); 
            } 
            catch (BadImageFormatException badImage) {
                Throw404(badImage); 
            }

            return assembly;
        } 

        private static Pair GetAssemblyInfo(Assembly assembly) { 
            Pair assemblyInfo = 
                (Pair)_assemblyInfoCache[assembly];
            if (assemblyInfo == null) { 
                assemblyInfo = GetAssemblyInfoInternal(assembly);
                _assemblyInfoCache[assembly] = assemblyInfo;
            }
            Debug.Assert(assemblyInfo != null, "Assembly info should not be null"); 
            return assemblyInfo;
        } 
 
        private static Pair GetAssemblyInfoInternal(Assembly assembly) {
            AssemblyName assemblyName = new AssemblyName(assembly.FullName); 
            return new Pair(assemblyName, GetLastWriteTime(assembly));
        }

        // AspNetHostingPermission attributes must be copied to this method, to satisfy FxCop rule 
        // CA2114:MethodSecurityShouldBeASupersetOfType.
        [ 
        AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal), 
        AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal),
        FileIOPermission(SecurityAction.Assert, AllFiles = FileIOPermissionAccess.PathDiscovery), 
        SecurityCritical
        ]
        private static string GetCodeBaseWithAssert(Assembly assembly) {
            return assembly.CodeBase; 
        }
 
        [ 
        SecurityCritical,
        SecurityTreatAsSafe 
        ]
        private static DateTime GetLastWriteTime(Assembly assembly) {
            string codeBase = GetCodeBaseWithAssert(assembly);
            Uri codeBaseUri = new Uri(codeBase); 
            if (!codeBaseUri.IsFile) {
                throw new InvalidOperationException(AtlasWeb.ScriptResourceHandler_AssemblyNotFileBased); 
            } 
            string localPath = codeBaseUri.LocalPath;
 
            FileIOPermission p = new FileIOPermission(FileIOPermissionAccess.Read, localPath);
            p.Assert();
            return File.GetLastWriteTime(localPath);
        } 

        internal static string GetScriptResourceUrl( 
            Assembly assembly, 
            string resourceName,
            CultureInfo culture, 
            bool zip,
            bool notifyScriptLoaded) {

            return _scriptResourceHandler 
                .GetScriptResourceUrl(assembly, resourceName, culture, zip, notifyScriptLoaded);
        } 
 
        // AspNetHostingPermission attributes must be copied to this method, to satisfy FxCop rule
        // CA2114:MethodSecurityShouldBeASupersetOfType. 
        [
        AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal),
        AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal),
        ReflectionPermission(SecurityAction.Assert, Unrestricted = true), 
        SecurityCritical,
        SecurityTreatAsSafe 
        ] 
        internal static string GetWebResourceUrl(Assembly assembly, string resourceName) {
            if (_getWebResourceUrl == null) { 
                lock (_getMethodLock) {
                    if (_getWebResourceUrl == null) {
                        _getWebResourceUrl = typeof(AssemblyResourceLoader)
                            .GetMethod("GetWebResourceUrlInternal", BindingFlags.Static | BindingFlags.NonPublic); 
                    }
                } 
            } 
            return (string)_getWebResourceUrl.Invoke(null, new object[] { assembly, resourceName, false });
        } 

        protected virtual bool IsReusable {
            get {
                return true; 
            }
        } 
 
        private static bool IsCompressionEnabled(HttpContext context) {
            return ScriptingScriptResourceHandlerSection.ApplicationSettings.EnableCompression && 
                ((context == null) ||
                !context.Request.Browser.IsBrowser("IE") ||
                (context.Request.Browser.MajorVersion > 6));
        } 

        internal static bool IsScriptResourceRequest(string path) { 
            return !String.IsNullOrEmpty(path) && 
                String.Equals(path, ScriptResourceAbsolutePath, StringComparison.OrdinalIgnoreCase);
        } 

        private static void PrepareResponseCache(HttpResponse response, Assembly assembly) {
            HttpCachePolicy cachePolicy = response.Cache;
            cachePolicy.SetCacheability(HttpCacheability.Public); 
            cachePolicy.VaryByParams["d"] = true;
            cachePolicy.SetOmitVaryStar(true); 
            cachePolicy.SetExpires(DateTime.Now + TimeSpan.FromDays(365)); 
            cachePolicy.SetValidUntilExpires(true);
            cachePolicy.SetLastModified((DateTime)GetAssemblyInfo(assembly).Second); 
        }

        private static void PrepareResponseNoCache(HttpResponse response, Assembly assembly) {
            HttpCachePolicy cachePolicy = response.Cache; 
            cachePolicy.SetCacheability(HttpCacheability.Public);
            cachePolicy.SetExpires(DateTime.Now + TimeSpan.FromDays(365)); 
            cachePolicy.SetValidUntilExpires(true); 
            cachePolicy.SetLastModified((DateTime)GetAssemblyInfo(assembly).Second);
            cachePolicy.SetNoServerCaching(); 
        }

        protected virtual void ProcessRequest(HttpContext context) {
            HttpResponse response = context.Response; 
            response.Clear();
 
            // Checking that the handler is not being called from a different path. 
            EnsureScriptResourceRequest(context.Request.Path);
 
            string decryptedString = DecryptParameter(context.Request.QueryString);

            bool zip = false;
            bool notifyScriptLoaded = true; 
            // See GetScriptResourceUrl comment below for first character meanings.
            switch(decryptedString[0]) { 
                case 'Z': 
                    zip = true;
                    break; 
                case 'z':
                    zip = true;
                    notifyScriptLoaded = false;
                    break; 
                case 'u':
                    notifyScriptLoaded = false; 
                    break; 
            }
 
            string[] decryptedData = decryptedString.Substring(1).Split('|');

            Debug.Assert(decryptedData.Length == 3, "The decrypted data must have three parts separated by pipes.");
 
            string assemblyName = decryptedData[0];
            string resourceName = decryptedData[1]; 
            string cultureName = decryptedData[2]; 

            if (String.IsNullOrEmpty(resourceName) || 
                String.IsNullOrEmpty(assemblyName)) {

                Throw404();
            } 

            Assembly assembly = GetAssembly(assemblyName); 
 
            if (assembly != null) {
                string script = null; 
                Encoding encoding;
                string contentType;
                try {
                    script = ScriptResourceAttribute.GetScriptFromWebResourceInternal( 
                        assembly, resourceName,
                        String.IsNullOrEmpty(cultureName) ? CultureInfo.InvariantCulture : new CultureInfo(cultureName), 
                        zip, notifyScriptLoaded, out encoding, out contentType); 
                }
                catch (MissingManifestResourceException ex) { 
                    throw Create404(ex);
                }
                catch (HttpException ex) {
                    throw Create404(ex); 
                }
 
                if (ScriptingScriptResourceHandlerSection.ApplicationSettings.EnableCaching) { 
                    PrepareResponseCache(response, assembly);
                } 
                else {
                    PrepareResponseNoCache(response, assembly);
                }
 
                response.ContentType = contentType;
 
                if (zip) { 
                    using (MemoryStream zipped = new MemoryStream()) {
                        using (Stream outputStream = new GZipStream(zipped, CompressionMode.Compress)) { 
                            using (StreamWriter writer = new StreamWriter(outputStream, encoding)) {
                                writer.Write(script);
                            }
                        } 
                        byte[] zippedBytes = zipped.ToArray();
                        response.AddHeader("Content-encoding", "gzip"); 
                        response.OutputStream.Write(zippedBytes, 0, zippedBytes.Length); 
                    }
                } 
                else {
                    response.ContentEncoding = encoding;
                    response.Write(script);
                } 
            }
            else { 
                Throw404(); 
            }
        } 

        internal static void SetScriptResourceHandler(IScriptResourceHandler scriptResourceHandler) {
            _scriptResourceHandler = scriptResourceHandler;
        } 

        private static void Throw404() { 
            throw Create404(null); 
        }
 
        private static void Throw404(Exception innerException) {
            throw Create404(innerException);
        }
 
        #region IHttpHandler implementation
        void IHttpHandler.ProcessRequest(HttpContext context) { 
            ProcessRequest(context); 
        }
 
        bool IHttpHandler.IsReusable {
            get {
                return IsReusable;
            } 
        }
        #endregion 
 
        private class RuntimeScriptResourceHandler : IScriptResourceHandler {
 
            private static readonly IDictionary _urlCache = Hashtable.Synchronized(new Hashtable());
            private static string _absoluteScriptResourceUrl;

            string IScriptResourceHandler.GetScriptResourceUrl( 
                Assembly assembly, string resourceName, CultureInfo culture, bool zip, bool notifyScriptLoaded) {
 
                if (!IsCompressionEnabled(HttpContext.Current)) { 
                    zip = false;
                } 

                Tuple cacheKey = new Tuple(assembly, resourceName, culture, zip, notifyScriptLoaded);

                string url = (string)_urlCache[cacheKey]; 

                if (url == null) { 
                    // Check if the resources exist 
                    ScriptResourceInfo resourceInfo = ScriptResourceInfo.GetInstance(assembly, resourceName);
                    if (resourceInfo == ScriptResourceInfo.Empty) { 
                        ThrowUnknownResource(resourceName);
                    }
                    Stream scriptStream = assembly.GetManifestResourceStream(resourceInfo.ScriptName);
                    if (scriptStream == null) { 
                        ThrowUnknownResource(resourceName);
                    } 
                    culture = DetermineNearestAvailableCulture(assembly, resourceName, culture); 

                    Pair assemblyInfo = GetAssemblyInfo(assembly); 

                    AssemblyName assemblyName = (AssemblyName)assemblyInfo.First;
                    DateTime assemblyDate = (DateTime)assemblyInfo.Second;
 
                    string urlAssemblyName;
 
                    if (assembly.GlobalAssemblyCache) { 
                        // If the assembly is in the GAC, we need to store a full name to load the assembly later
                        // Pack the necessary values into a more compact format than FullName 
                        StringBuilder builder = new StringBuilder();
                        builder.Append(assemblyName.Name);
                        builder.Append(',');
                        builder.Append(assemblyName.Version); 
                        builder.Append(',');
                        if (assemblyName.CultureInfo != null) { 
                            builder.Append(assemblyName.CultureInfo); 
                        }
                        builder.Append(','); 
                        builder.Append(HexParser.ToString(assemblyName.GetPublicKeyToken()));
                        urlAssemblyName = builder.ToString();
                    }
                    else { 
                        // Otherwise, we can just use a partial name
                        urlAssemblyName = assemblyName.Name; 
                    } 

                    // First character of the encoded string is: 
                    // Z: compressed, append notifycriptLoaded
                    // z: compressed, don't append notifyScriptLoaded
                    // U: non-compressed, append notifyScriptLoaded
                    // u: non-compressed, don't append notifyScriptLoaded 

                    if (_absoluteScriptResourceUrl == null) { 
                        _absoluteScriptResourceUrl = VirtualPathUtility.ToAbsolute(_scriptResourceUrl); 
                    }
 
                    url = _absoluteScriptResourceUrl + "?d=" +
                        Page.EncryptString(
                            (zip ? (notifyScriptLoaded ? "Z" : "z") : (notifyScriptLoaded ? "U" : "u")) +
                            urlAssemblyName + "|" + 
                            resourceName + "|" +
                            culture.ToString()) + 
                        "&t=" + assemblyDate.Ticks; 

                    _urlCache[cacheKey] = url; 
                }

                return url;
            } 

            private static void ThrowUnknownResource(string resourceName) { 
                throw new HttpException(String.Format(CultureInfo.CurrentCulture, 
                    AtlasWeb.ScriptResourceHandler_UnknownResource, resourceName));
            } 
        }
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK