Exemplo n.º 1
0
            private static string GetScriptResourceUrlImpl(
                List <Tuple <Assembly, List <Tuple <string, CultureInfo> > > > assemblyResourceLists,
                bool zip)
            {
                EnsureAbsoluteScriptResourceUrl();

                // If there's only a single assembly resource, format is
                //      [Z|U|z|u]<assembly>|<resource>|<culture>
                // If there are multiple resources, or a single resource that is path based, format is
                //      [Q|R|q|r]<assembly1>|<resource1a>,<culture1a>,<resource1b>,<culture1b>...|<assembly2>|<resource2a>,<culture2a>,<resource2b>,<culture2b>...
                // A path based reference has no assembly (empty).
                // (the Q/R indicators used in place of Z/U give the handler indiciation that the url is a composite
                // reference, and allows for System.Web.Extensions SP1 to maintain compatibility with RTM, should a
                // single resource be encrypted with SP1 and decrypted with RTM).

                bool singleAssemblyResource = false;

                if (assemblyResourceLists.Count == 1)
                {
                    // only one assembly to pull from...
                    var reference = assemblyResourceLists[0];
                    if ((reference.Item1 != null) && (reference.Item2.Count == 1))
                    {
                        // resource is assembly not path, and there's only one resource within it to load
                        singleAssemblyResource = true;
                    }
                }

                // Next character of the encoded string is:
                // Format: S = Single Assembly Reference, C = Composite Reference or Single Path Reference
                // Zip: compress or not (true or false)
                // First    Format  Zip?
                // =====================
                // Z        S       T
                // U        S       F
                // Q        C       T
                // R        C       F

                string indicator;

                if (singleAssemblyResource)
                {
                    indicator = (zip ? "Z" : "U");
                }
                else
                {
                    indicator = (zip ? "Q" : "R");
                }

                StringBuilder url = new StringBuilder(indicator);

                HashCodeCombiner hashCombiner = new HashCodeCombiner();

                bool firstAssembly = true;

                foreach (Tuple <Assembly, List <Tuple <string, CultureInfo> > > assemblyData in assemblyResourceLists)
                {
                    if (!firstAssembly)
                    {
                        url.Append('|');
                    }
                    else
                    {
                        firstAssembly = false;
                    }
                    if (assemblyData.Item1 != null)
                    {
                        Tuple <AssemblyName, String> assemblyInfo = GetAssemblyInfo(assemblyData.Item1);

                        AssemblyName assemblyName = (AssemblyName)assemblyInfo.Item1;
                        string       assemblyHash = (String)assemblyInfo.Item2;
                        hashCombiner.AddObject(assemblyHash);

                        if (assemblyData.Item1.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
                            url.Append(assemblyName.Name);
                            url.Append(',');
                            url.Append(assemblyName.Version);
                            url.Append(',');
                            if (assemblyName.CultureInfo != null)
                            {
                                url.Append(assemblyName.CultureInfo);
                            }
                            url.Append(',');
                            url.Append(HexParser.ToString(assemblyName.GetPublicKeyToken()));
                        }
                        else
                        {
                            // Otherwise, we can just use a partial name
                            url.Append(assemblyName.Name);
                        }
                    }
                    url.Append('|');

                    bool firstResource = true;
                    foreach (Tuple <string, CultureInfo> resourceAndCulture in assemblyData.Item2)
                    {
                        if (!firstResource)
                        {
                            url.Append(',');
                        }

                        if (assemblyData.Item1 != null)
                        {
                            url.Append(resourceAndCulture.Item1);
                            Tuple <Assembly, string, CultureInfo> cacheKey = Tuple.Create(
                                assemblyData.Item1,
                                resourceAndCulture.Item1,
                                resourceAndCulture.Item2
                                );
                            string cultureName = (string)_cultureCache[cacheKey];
                            if (cultureName == null)
                            {
                                // Check if the resources exist
                                ScriptResourceInfo resourceInfo =
                                    ScriptResourceInfo.GetInstance(assemblyData.Item1, resourceAndCulture.Item1);
                                if (resourceInfo == ScriptResourceInfo.Empty)
                                {
                                    ThrowUnknownResource(resourceAndCulture.Item1);
                                }
                                Stream scriptStream = assemblyData.Item1.GetManifestResourceStream(resourceInfo.ScriptName);
                                if (scriptStream == null)
                                {
                                    ThrowUnknownResource(resourceAndCulture.Item1);
                                }
                                cultureName = DetermineNearestAvailableCulture(
                                    assemblyData.Item1, resourceAndCulture.Item1, resourceAndCulture.Item2).Name;
                                _cultureCache[cacheKey] = cultureName;
                            }
                            url.Append(singleAssemblyResource ? "|" : ",");
                            url.Append(cultureName);
                        }
                        else
                        {
                            Debug.Assert(!singleAssemblyResource, "This should never happen since this is a path reference.");

                            if (!_bypassVirtualPathResolution)
                            {
                                VirtualPathProvider vpp = HostingEnvironment.VirtualPathProvider;
                                if (!vpp.FileExists(resourceAndCulture.Item1))
                                {
                                    ThrowUnknownResource(resourceAndCulture.Item1);
                                }
                                string hash = vpp.GetFileHash(resourceAndCulture.Item1, new string[] { resourceAndCulture.Item1 });
                                hashCombiner.AddObject(hash);
                            }
                            url.Append(resourceAndCulture.Item1);
                        }
                        firstResource = false;
                    }
                }

                // DevDiv Bugs 186624: The hash code needs to be part of the encrypted blob for composite scripts
                // because we cache the composite script on the server using a VaryByParam["d"]. Otherwise, if a
                // path based script in the composite changes, only the 't' parameter would change, which would
                // cause a new request to the server, but it would be served via cache since 'd' would be the same.
                // This isn't a problem for assembly based resources since changing them also restarts the app and
                // clears the cache. We do not vary by 't' because that makes it possible to flood the server cache
                // with cache entries, since anything could be used for 't'. Putting the hash in 'd' ensures a different
                // url and different cache entry when a script changes, but without the possibility of flooding
                // the server cache.

                // However, we continue to use the 't' parameter for single assembly references for compatibility.

                string resourceUrl;

                if (singleAssemblyResource)
                {
                    resourceUrl = _absoluteScriptResourceUrl +
                                  Page.EncryptString(url.ToString(), Purpose.ScriptResourceHandler_ScriptResourceUrl) +
                                  "&t=" + hashCombiner.CombinedHashString;
                }
                else
                {
                    // note that CombinedHashString is hex, it will never include a '|' that would confuse the handler.
                    url.Append("|#|");
                    url.Append(hashCombiner.CombinedHashString);
                    resourceUrl = _absoluteScriptResourceUrl +
                                  Page.EncryptString(url.ToString(), Purpose.ScriptResourceHandler_ScriptResourceUrl);
                }

                if (resourceUrl.Length > _maximumResourceUrlLength)
                {
                    throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, AtlasWeb.ScriptResourceHandler_ResourceUrlTooLong, _maximumResourceUrlLength));
                }
                return(resourceUrl);
            }
Exemplo n.º 2
0
        internal static CultureInfo DetermineNearestAvailableCulture(
            Assembly assembly,
            string scriptResourceName,
            CultureInfo culture)
        {
            if (String.IsNullOrEmpty(scriptResourceName))
            {
                return(CultureInfo.InvariantCulture);
            }

            Tuple <Assembly, string, CultureInfo> cacheKey = Tuple.Create(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;
                }
                // Neutral assembly culture falls back on invariant
                CultureInfo neutralCulture = GetAssemblyNeutralCulture(assembly);
                if ((neutralCulture != null) && neutralCulture.Equals(culture))
                {
                    culture = CultureInfo.InvariantCulture;
                }
                cachedCulture           = culture;
                _cultureCache[cacheKey] = cachedCulture;
            }
            return(cachedCulture);
        }