public override string GetFileHash(string virtualPath, IEnumerable virtualPathDependencies)
        {
            string debugPath = ResolveDebugFilePath(virtualPath);

            if (debugPath != null)
            {
                return(File.GetLastWriteTime(debugPath).ToString());
            }

            return(_previous.GetFileHash(virtualPath, virtualPathDependencies));
        }
Exemple #2
0
 public override string GetFileHash(string virtualPath, System.Collections.IEnumerable virtualPathDependencies)
 {
     if (!IsAppResourcePath(virtualPath))
     {
         return(parent.GetFileHash(virtualPath, virtualPathDependencies));
     }
     else
     {
         return(base.GetFileHash(virtualPath, virtualPathDependencies));
     }
 }
        public override string GetFileHash(string virtualPath, IEnumerable virtualPathDependencies)
        {
            if (virtualPathDependencies == null)
            {
                return(_previous.GetFileHash(virtualPath, virtualPathDependencies));
            }

            var fileNames = MapDependencyPaths(virtualPathDependencies.Cast <string>(), out _);
            var combiner  = HashCodeCombiner.Start();

            foreach (var fileName in fileNames)
            {
                combiner.Add(new FileInfo(fileName));
            }

            return(combiner.CombinedHashString);
        }
Exemple #4
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);
            }